Browse Source

hls muxer: avoid infinite loop when hlsAlwaysRemux is true

when hlsAlwaysRemux is true and a muxer fails, add a pause between its
recreation, in order to avoid infinite loops
pull/1377/head
aler9 4 years ago
parent
commit
7420ef1ce4
  1. 120
      internal/core/hls_muxer.go
  2. 5
      internal/core/hls_server.go

120
internal/core/hls_muxer.go

@ -25,8 +25,9 @@ import (
) )
const ( const (
closeCheckPeriod = 1 * time.Second closeCheckPeriod = 1 * time.Second
closeAfterInactivity = 60 * time.Second closeAfterInactivity = 60 * time.Second
hlsMuxerRecreatePause = 10 * time.Second
) )
//go:embed hls_index.html //go:embed hls_index.html
@ -57,11 +58,12 @@ type hlsMuxer struct {
name string name string
remoteAddr string remoteAddr string
externalAuthenticationURL string externalAuthenticationURL string
hlsVariant conf.HLSVariant alwaysRemux bool
hlsSegmentCount int variant conf.HLSVariant
hlsSegmentDuration conf.StringDuration segmentCount int
hlsPartDuration conf.StringDuration segmentDuration conf.StringDuration
hlsSegmentMaxSize conf.StringSize partDuration conf.StringDuration
segmentMaxSize conf.StringSize
readBufferCount int readBufferCount int
wg *sync.WaitGroup wg *sync.WaitGroup
pathName string pathName string
@ -88,11 +90,12 @@ func newHLSMuxer(
name string, name string,
remoteAddr string, remoteAddr string,
externalAuthenticationURL string, externalAuthenticationURL string,
hlsVariant conf.HLSVariant, alwaysRemux bool,
hlsSegmentCount int, variant conf.HLSVariant,
hlsSegmentDuration conf.StringDuration, segmentCount int,
hlsPartDuration conf.StringDuration, segmentDuration conf.StringDuration,
hlsSegmentMaxSize conf.StringSize, partDuration conf.StringDuration,
segmentMaxSize conf.StringSize,
readBufferCount int, readBufferCount int,
req *hlsMuxerRequest, req *hlsMuxerRequest,
wg *sync.WaitGroup, wg *sync.WaitGroup,
@ -106,11 +109,12 @@ func newHLSMuxer(
name: name, name: name,
remoteAddr: remoteAddr, remoteAddr: remoteAddr,
externalAuthenticationURL: externalAuthenticationURL, externalAuthenticationURL: externalAuthenticationURL,
hlsVariant: hlsVariant, alwaysRemux: alwaysRemux,
hlsSegmentCount: hlsSegmentCount, variant: variant,
hlsSegmentDuration: hlsSegmentDuration, segmentCount: segmentCount,
hlsPartDuration: hlsPartDuration, segmentDuration: segmentDuration,
hlsSegmentMaxSize: hlsSegmentMaxSize, partDuration: partDuration,
segmentMaxSize: segmentMaxSize,
readBufferCount: readBufferCount, readBufferCount: readBufferCount,
wg: wg, wg: wg,
pathName: pathName, pathName: pathName,
@ -161,21 +165,34 @@ func (m *hlsMuxer) PathName() string {
func (m *hlsMuxer) run() { func (m *hlsMuxer) run() {
defer m.wg.Done() defer m.wg.Done()
innerCtx, innerCtxCancel := context.WithCancel(context.Background()) err := func() error {
innerReady := make(chan struct{}) var innerReady chan struct{}
innerErr := make(chan error) var innerErr chan error
go func() { var innerCtx context.Context
innerErr <- m.runInner(innerCtx, innerReady) var innerCtxCancel func()
}()
createInner := func() {
innerReady = make(chan struct{})
innerErr = make(chan error)
innerCtx, innerCtxCancel = context.WithCancel(context.Background())
go func() {
innerErr <- m.runInner(innerCtx, innerReady)
}()
}
isReady := false createInner()
isReady := false
isRecreating := false
recreateTimer := newEmptyTimer()
err := func() error {
for { for {
select { select {
case <-m.ctx.Done(): case <-m.ctx.Done():
innerCtxCancel() if !isRecreating {
<-innerErr innerCtxCancel()
<-innerErr
}
return errors.New("terminated") return errors.New("terminated")
case req := <-m.chRequest: case req := <-m.chRequest:
@ -208,13 +225,34 @@ func (m *hlsMuxer) run() {
case err := <-innerErr: case err := <-innerErr:
innerCtxCancel() innerCtxCancel()
return err
if m.alwaysRemux {
m.log(logger.Info, "ERR: %v", err)
m.clearQueuedRequests()
isReady = false
isRecreating = true
recreateTimer = time.NewTimer(hlsMuxerRecreatePause)
} else {
return err
}
case <-recreateTimer.C:
isRecreating = false
createInner()
} }
} }
}() }()
m.ctxCancel() m.ctxCancel()
m.clearQueuedRequests()
m.parent.muxerClose(m)
m.log(logger.Info, "destroyed (%v)", err)
}
func (m *hlsMuxer) clearQueuedRequests() {
for _, req := range m.requests { for _, req := range m.requests {
req.res <- hlsMuxerResponse{ req.res <- hlsMuxerResponse{
muxer: m, muxer: m,
@ -223,10 +261,6 @@ func (m *hlsMuxer) run() {
}, },
} }
} }
m.parent.muxerClose(m)
m.log(logger.Info, "destroyed (%v)", err)
} }
func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) error { func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) error {
@ -267,11 +301,11 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
var err error var err error
m.muxer, err = hls.NewMuxer( m.muxer, err = hls.NewMuxer(
hls.MuxerVariant(m.hlsVariant), hls.MuxerVariant(m.variant),
m.hlsSegmentCount, m.segmentCount,
time.Duration(m.hlsSegmentDuration), time.Duration(m.segmentDuration),
time.Duration(m.hlsPartDuration), time.Duration(m.partDuration),
uint64(m.hlsSegmentMaxSize), uint64(m.segmentMaxSize),
videoFormat, videoFormat,
audioFormat, audioFormat,
) )
@ -296,11 +330,13 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
for { for {
select { select {
case <-closeCheckTicker.C: case <-closeCheckTicker.C:
t := time.Unix(0, atomic.LoadInt64(m.lastRequestTime)) if m.remoteAddr != "" {
if m.remoteAddr != "" && time.Since(t) >= closeAfterInactivity { t := time.Unix(0, atomic.LoadInt64(m.lastRequestTime))
m.ringBuffer.Close() if time.Since(t) >= closeAfterInactivity {
<-writerDone m.ringBuffer.Close()
return fmt.Errorf("not used anymore") <-writerDone
return fmt.Errorf("not used anymore")
}
} }
case err := <-writerDone: case err := <-writerDone:

5
internal/core/hls_server.go

@ -225,10 +225,6 @@ outer:
} }
delete(s.muxers, c.PathName()) delete(s.muxers, c.PathName())
if s.alwaysRemux && c.remoteAddr == "" {
s.findOrCreateMuxer(c.PathName(), "", nil)
}
case req := <-s.chAPIMuxerList: case req := <-s.chAPIMuxerList:
muxers := make(map[string]*hlsMuxer) muxers := make(map[string]*hlsMuxer)
@ -339,6 +335,7 @@ func (s *hlsServer) findOrCreateMuxer(pathName string, remoteAddr string, req *h
pathName, pathName,
remoteAddr, remoteAddr,
s.externalAuthenticationURL, s.externalAuthenticationURL,
s.alwaysRemux,
s.variant, s.variant,
s.segmentCount, s.segmentCount,
s.segmentDuration, s.segmentDuration,

Loading…
Cancel
Save