feat: Prevent concurrent read and write issues when publishers catch up with subscribers after blocking them

desc: 防止订阅者阻塞后,发布者追上订阅者产生并发读写问题
This commit is contained in:
langhuihui
2023-06-30 09:57:52 +08:00
parent 700aef98c5
commit 6a4610df1d
17 changed files with 397 additions and 282 deletions

View File

@@ -9,6 +9,7 @@ import (
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"m7s.live/engine/v4/codec"
. "m7s.live/engine/v4/common"
"m7s.live/engine/v4/config"
@@ -206,9 +207,10 @@ func (s *Subscriber) PlayBlock(subType byte) {
ctx := s.TrackPlayer.Context
conf := s.Config
hasVideo, hasAudio := s.Video != nil && conf.SubVideo, s.Audio != nil && conf.SubAudio
defer s.onStop()
stopReason := zap.String("reason", "stop")
defer s.onStop(&stopReason)
if !hasAudio && !hasVideo {
s.Error("play neither video nor audio")
stopReason = zap.String("reason", "play neither video nor audio")
return
}
sendVideoDecConf := func() {
@@ -309,11 +311,12 @@ func (s *Subscriber) PlayBlock(subType byte) {
for ctx.Err() == nil {
if hasVideo {
for ctx.Err() == nil {
s.VideoReader.Read(ctx, subMode)
videoFrame = s.VideoReader.Frame
if videoFrame == nil || ctx.Err() != nil {
err := s.VideoReader.ReadFrame(subMode)
if err != nil {
stopReason = zap.Error(err)
return
}
videoFrame = s.VideoReader.Value
// fmt.Println("video", s.VideoReader.Track.PreFrame().Sequence-frame.Sequence)
if videoFrame.IFrame && s.VideoReader.DecConfChanged() {
s.VideoReader.ConfSeq = s.VideoReader.Track.SequenceHeadSeq
@@ -323,9 +326,7 @@ func (s *Subscriber) PlayBlock(subType byte) {
if audioFrame != nil {
if videoFrame.Timestamp > audioFrame.Timestamp {
// fmt.Println("switch audio", audioFrame.CanRead)
if audioFrame.CanRead {
sendAudioFrame(audioFrame)
}
sendAudioFrame(audioFrame)
audioFrame = nil
break
}
@@ -355,11 +356,12 @@ func (s *Subscriber) PlayBlock(subType byte) {
s.AudioReader.SkipTs = s.VideoReader.SkipTs
}
}
s.AudioReader.Read(ctx, subMode)
audioFrame = s.AudioReader.Frame
if audioFrame == nil || ctx.Err() != nil {
err := s.AudioReader.ReadFrame(subMode)
if err != nil {
stopReason = zap.Error(err)
return
}
audioFrame = s.AudioReader.Value
// fmt.Println("audio", s.AudioReader.Track.PreFrame().Sequence-frame.Sequence)
if s.AudioReader.DecConfChanged() {
s.AudioReader.ConfSeq = s.AudioReader.Track.SequenceHeadSeq
@@ -368,9 +370,7 @@ func (s *Subscriber) PlayBlock(subType byte) {
if hasVideo && videoFrame != nil {
if audioFrame.Timestamp > videoFrame.Timestamp {
// fmt.Println("switch video", videoFrame.CanRead)
if videoFrame.CanRead {
sendVideoFrame(videoFrame)
}
sendVideoFrame(videoFrame)
videoFrame = nil
break
}
@@ -383,11 +383,18 @@ func (s *Subscriber) PlayBlock(subType byte) {
}
}
}
if videoFrame != nil {
videoFrame.ReaderLeave()
}
if audioFrame != nil {
audioFrame.ReaderLeave()
}
stopReason = zap.Error(ctx.Err())
}
func (s *Subscriber) onStop() {
func (s *Subscriber) onStop(reason *zapcore.Field) {
if !s.Stream.IsClosed() {
s.Info("stop")
s.Info("stop", *reason)
if !s.Config.Internal {
s.Stream.Receive(s.Spesific)
}