Browse Source

hls: fix freeze when sourceOnDemand is yes and multiple sources are requested at the same time (#493)

pull/509/head
aler9 5 years ago
parent
commit
3872b42434
  1. 82
      internal/core/hls_remuxer.go

82
internal/core/hls_remuxer.go

@ -111,6 +111,7 @@ type hlsRemuxer struct {
ringBuffer *ringbuffer.RingBuffer ringBuffer *ringbuffer.RingBuffer
lastRequestTime *int64 lastRequestTime *int64
muxer *hls.Muxer muxer *hls.Muxer
requests []hlsRemuxerRequest
// in // in
request chan hlsRemuxerRequest request chan hlsRemuxerRequest
@ -177,22 +178,44 @@ func (r *hlsRemuxer) PathName() string {
func (r *hlsRemuxer) run() { func (r *hlsRemuxer) run() {
defer r.wg.Done() defer r.wg.Done()
innerCtx, innerCtxCancel := context.WithCancel(context.Background()) remuxerCtx, remuxerCtxCancel := context.WithCancel(context.Background())
runErr := make(chan error) remuxerReady := make(chan struct{})
remuxerErr := make(chan error)
go func() { go func() {
runErr <- r.runInner(innerCtx) remuxerErr <- r.runRemuxer(remuxerCtx, remuxerReady)
}() }()
isReady := false
outer:
for {
select { select {
case err := <-runErr: case <-r.ctx.Done():
innerCtxCancel() remuxerCtxCancel()
<-remuxerErr
break outer
case req := <-r.request:
if isReady {
r.handleRequest(req)
} else {
r.requests = append(r.requests, req)
}
case <-remuxerReady:
isReady = true
for _, req := range r.requests {
r.handleRequest(req)
}
r.requests = nil
case err := <-remuxerErr:
remuxerCtxCancel()
if err != nil { if err != nil {
r.log(logger.Info, "ERR: %s", err) r.log(logger.Info, "ERR: %s", err)
} }
break outer
case <-r.ctx.Done(): }
innerCtxCancel()
<-runErr
} }
r.ctxCancel() r.ctxCancel()
@ -200,14 +223,13 @@ func (r *hlsRemuxer) run() {
r.parent.OnRemuxerClose(r) r.parent.OnRemuxerClose(r)
} }
func (r *hlsRemuxer) runInner(innerCtx context.Context) error { func (r *hlsRemuxer) runRemuxer(remuxerCtx context.Context, remuxerReady chan struct{}) error {
res := r.pathManager.OnReaderSetupPlay(pathReaderSetupPlayReq{ res := r.pathManager.OnReaderSetupPlay(pathReaderSetupPlayReq{
Author: r, Author: r,
PathName: r.pathName, PathName: r.pathName,
IP: nil, IP: nil,
ValidateCredentials: nil, ValidateCredentials: nil,
}) })
if res.Err != nil { if res.Err != nil {
return res.Err return res.Err
} }
@ -283,21 +305,11 @@ func (r *hlsRemuxer) runInner(innerCtx context.Context) error {
} }
defer r.muxer.Close() defer r.muxer.Close()
// start request handler only after muxer has been inizialized remuxerReady <- struct{}{}
requestHandlerTerminate := make(chan struct{})
requestHandlerDone := make(chan struct{})
go r.runRequestHandler(requestHandlerTerminate, requestHandlerDone)
defer func() {
close(requestHandlerTerminate)
<-requestHandlerDone
}()
r.ringBuffer = ringbuffer.New(uint64(r.readBufferCount)) r.ringBuffer = ringbuffer.New(uint64(r.readBufferCount))
r.path.OnReaderPlay(pathReaderPlayReq{ r.path.OnReaderPlay(pathReaderPlayReq{Author: r})
Author: r,
})
writerDone := make(chan error) writerDone := make(chan error)
go func() { go func() {
@ -396,7 +408,7 @@ func (r *hlsRemuxer) runInner(innerCtx context.Context) error {
case err := <-writerDone: case err := <-writerDone:
return err return err
case <-innerCtx.Done(): case <-remuxerCtx.Done():
r.ringBuffer.Close() r.ringBuffer.Close()
<-writerDone <-writerDone
return nil return nil
@ -404,17 +416,7 @@ func (r *hlsRemuxer) runInner(innerCtx context.Context) error {
} }
} }
func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct{}) { func (r *hlsRemuxer) handleRequest(req hlsRemuxerRequest) {
defer close(done)
for {
select {
case <-terminate:
return
case preq := <-r.request:
req := preq
atomic.StoreInt64(r.lastRequestTime, time.Now().Unix()) atomic.StoreInt64(r.lastRequestTime, time.Now().Unix())
conf := r.path.Conf() conf := r.path.Conf()
@ -426,7 +428,7 @@ func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct
r.log(logger.Info, "ERR: ip '%s' not allowed", ip) r.log(logger.Info, "ERR: ip '%s' not allowed", ip)
req.W.WriteHeader(http.StatusUnauthorized) req.W.WriteHeader(http.StatusUnauthorized)
req.Res <- nil req.Res <- nil
continue return
} }
} }
@ -436,7 +438,7 @@ func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct
req.W.Header().Set("WWW-Authenticate", `Basic realm="rtsp-simple-server"`) req.W.Header().Set("WWW-Authenticate", `Basic realm="rtsp-simple-server"`)
req.W.WriteHeader(http.StatusUnauthorized) req.W.WriteHeader(http.StatusUnauthorized)
req.Res <- nil req.Res <- nil
continue return
} }
} }
@ -446,7 +448,7 @@ func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct
if r == nil { if r == nil {
req.W.WriteHeader(http.StatusNotFound) req.W.WriteHeader(http.StatusNotFound)
req.Res <- nil req.Res <- nil
continue return
} }
req.W.Header().Set("Content-Type", `application/x-mpegURL`) req.W.Header().Set("Content-Type", `application/x-mpegURL`)
@ -457,7 +459,7 @@ func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct
if r == nil { if r == nil {
req.W.WriteHeader(http.StatusNotFound) req.W.WriteHeader(http.StatusNotFound)
req.Res <- nil req.Res <- nil
continue return
} }
req.W.Header().Set("Content-Type", `video/MP2T`) req.W.Header().Set("Content-Type", `video/MP2T`)
@ -470,8 +472,6 @@ func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct
req.W.WriteHeader(http.StatusNotFound) req.W.WriteHeader(http.StatusNotFound)
req.Res <- nil req.Res <- nil
} }
}
}
} }
// OnRequest is called by hlsserver.Server (forwarded from ServeHTTP). // OnRequest is called by hlsserver.Server (forwarded from ServeHTTP).

Loading…
Cancel
Save