|
|
|
@ -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`) |
|
|
|
@ -471,8 +473,6 @@ func (r *hlsRemuxer) runRequestHandler(terminate chan struct{}, done chan struct |
|
|
|
req.Res <- nil |
|
|
|
req.Res <- nil |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// OnRequest is called by hlsserver.Server (forwarded from ServeHTTP).
|
|
|
|
// OnRequest is called by hlsserver.Server (forwarded from ServeHTTP).
|
|
|
|
func (r *hlsRemuxer) OnRequest(req hlsRemuxerRequest) { |
|
|
|
func (r *hlsRemuxer) OnRequest(req hlsRemuxerRequest) { |
|
|
|
|