mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-05 00:32:44 +08:00
大改版
This commit is contained in:
176
subscriber.go
176
subscriber.go
@@ -2,14 +2,16 @@ package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/Monibuca/utils/v3/codec"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// SubscriberInfo 订阅者可序列化信息,用于控制台输出
|
||||
type SubscriberInfo struct {
|
||||
// Subscriber 订阅者实体定义
|
||||
type Subscriber struct {
|
||||
context.Context
|
||||
*Stream `json:"-"`
|
||||
ID string
|
||||
TotalDrop int //总丢帧
|
||||
TotalPacket int
|
||||
@@ -17,19 +19,12 @@ type SubscriberInfo struct {
|
||||
BufferLength int
|
||||
Delay uint32
|
||||
SubscribeTime time.Time
|
||||
}
|
||||
|
||||
// Subscriber 订阅者实体定义
|
||||
type Subscriber struct {
|
||||
context.Context
|
||||
*Stream `json:"-"`
|
||||
SubscriberInfo
|
||||
cancel context.CancelFunc
|
||||
Sign string
|
||||
OffsetTime uint32
|
||||
startTime uint32
|
||||
vtIndex int //第几个视频轨
|
||||
atIndex int //第几个音频轨
|
||||
cancel context.CancelFunc
|
||||
Sign string
|
||||
OffsetTime uint32
|
||||
startTime uint32
|
||||
OnAudio func(pack AudioPack) `json:"-"`
|
||||
OnVideo func(pack VideoPack) `json:"-"`
|
||||
}
|
||||
|
||||
// IsClosed 检查订阅者是否已经关闭
|
||||
@@ -44,14 +39,41 @@ func (s *Subscriber) Close() {
|
||||
s.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subscriber) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.SubscriberInfo)
|
||||
func (r *Subscriber) GetVideoTrack(codec string) *VideoTrack {
|
||||
if !config.EnableVideo {
|
||||
return nil
|
||||
}
|
||||
r.videoRW.RLock()
|
||||
defer r.videoRW.RUnlock()
|
||||
return r.VideoTracks[codec]
|
||||
}
|
||||
func (s *Subscriber) GetAudioTrack(codecs ...string) (at *AudioTrack) {
|
||||
if !config.EnableAudio {
|
||||
return nil
|
||||
}
|
||||
if HasTranscoder {
|
||||
s.audioRW.Lock()
|
||||
defer s.audioRW.Unlock()
|
||||
} else {
|
||||
s.audioRW.RLock()
|
||||
defer s.audioRW.RUnlock()
|
||||
}
|
||||
for _, codec := range codecs {
|
||||
if at, ok := s.AudioTracks[codec]; ok {
|
||||
return at
|
||||
}
|
||||
}
|
||||
if HasTranscoder {
|
||||
at = s.AddAudioTrack(codecs[0], nil)
|
||||
at.SoundFormat = codec.Codec2SoundFormat[codecs[0]]
|
||||
TriggerHook(Hook{HOOK_REQUEST_TRANSAUDIO, &TransCodeReq{s, codecs[0]}})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//Subscribe 开始订阅
|
||||
//Subscribe 开始订阅 将Subscriber与Stream关联
|
||||
func (s *Subscriber) Subscribe(streamPath string) error {
|
||||
if !config.EnableWaitStream && FindStream(streamPath) == nil {
|
||||
if FindStream(streamPath) == nil {
|
||||
return errors.Errorf("Stream not found:%s", streamPath)
|
||||
}
|
||||
GetStream(streamPath).Subscribe(s)
|
||||
@@ -60,3 +82,115 @@ func (s *Subscriber) Subscribe(streamPath string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//Play 开始播放
|
||||
func (s *Subscriber) Play(ctx context.Context, at *AudioTrack, vt *VideoTrack) {
|
||||
defer s.Close()
|
||||
if vt == nil && at == nil {
|
||||
return
|
||||
}
|
||||
if vt == nil {
|
||||
s.PlayAudio(ctx, at)
|
||||
return
|
||||
} else if at == nil {
|
||||
s.PlayVideo(ctx, vt)
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-vt.WaitFirst: //等待获取到第一个关键帧
|
||||
case <-s.Context.Done():
|
||||
return
|
||||
case <-ctx.Done(): //可能等不到关键帧就退出了
|
||||
return
|
||||
}
|
||||
vr := vt.Buffer.SubRing(vt.FirstScreen) //从关键帧开始读取,首屏秒开
|
||||
vr.Current.Wait() //等到RingBuffer可读
|
||||
ar := at.Buffer.SubRing(at.Buffer.Index)
|
||||
ar.Current.Wait()
|
||||
dropping := false //是否处于丢帧中
|
||||
send_audio := func() {
|
||||
s.OnAudio(ar.Current.AudioPack)
|
||||
if at.Buffer.Index-ar.Index > 128 {
|
||||
dropping = true
|
||||
}
|
||||
}
|
||||
send_video := func() {
|
||||
s.OnVideo(vr.Current.VideoPack)
|
||||
if vt.Buffer.Index-vr.Index > 128 {
|
||||
dropping = true
|
||||
}
|
||||
}
|
||||
for ctx.Err() == nil && s.Context.Err() == nil {
|
||||
if ar.Current.Timestamp > vr.Current.Timestamp || ar.Current.Timestamp == 0 {
|
||||
if !dropping {
|
||||
send_video()
|
||||
} else if vr.Current.NalType == codec.NALU_IDR_Picture {
|
||||
dropping = false
|
||||
}
|
||||
vr.NextR()
|
||||
} else {
|
||||
if !dropping {
|
||||
send_audio()
|
||||
}
|
||||
ar.NextR()
|
||||
}
|
||||
}
|
||||
}
|
||||
func (s *Subscriber) PlayAudio(ctx context.Context, at *AudioTrack) {
|
||||
ring := at.Buffer.SubRing(at.Buffer.Index)
|
||||
ring.Current.Wait()
|
||||
droped := 0
|
||||
var action, send func()
|
||||
drop := func() {
|
||||
if at.Buffer.Index-ring.Index < 10 {
|
||||
action = send
|
||||
} else {
|
||||
droped++
|
||||
}
|
||||
}
|
||||
send = func() {
|
||||
s.OnAudio(ring.Current.AudioPack)
|
||||
|
||||
//s.BufferLength = pIndex - ring.Index
|
||||
//s.Delay = s.AVRing.Timestamp - packet.Timestamp
|
||||
if at.Buffer.Index-ring.Index > 128 {
|
||||
action = drop
|
||||
}
|
||||
}
|
||||
for action = send; ctx.Err() == nil && s.Context.Err() == nil; ring.NextR() {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Subscriber) PlayVideo(ctx context.Context, vt *VideoTrack) {
|
||||
select {
|
||||
case <-vt.WaitFirst:
|
||||
case <-s.Context.Done():
|
||||
return
|
||||
case <-ctx.Done(): //可能等不到关键帧就退出了
|
||||
return
|
||||
}
|
||||
ring := vt.Buffer.SubRing(vt.FirstScreen)
|
||||
ring.Current.Wait()
|
||||
droped := 0
|
||||
var action, send func()
|
||||
drop := func() {
|
||||
if ring.Current.NalType == codec.NALU_IDR_Picture {
|
||||
action = send
|
||||
} else {
|
||||
droped++
|
||||
}
|
||||
}
|
||||
send = func() {
|
||||
s.OnVideo(ring.Current.VideoPack)
|
||||
pIndex := vt.Buffer.Index
|
||||
//s.BufferLength = pIndex - ring.Index
|
||||
//s.Delay = s.AVRing.Timestamp - packet.Timestamp
|
||||
if pIndex-ring.Index > 128 {
|
||||
action = drop
|
||||
}
|
||||
}
|
||||
for action = send; ctx.Err() == nil && s.Context.Err() == nil; ring.NextR() {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user