mirror of
https://github.com/bluenviron/mediamtx
synced 2025-01-23 23:42:59 +00:00
166 lines
3.5 KiB
Go
166 lines
3.5 KiB
Go
|
package core
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"github.com/aler9/rtsp-simple-server/internal/conf"
|
||
|
"github.com/aler9/rtsp-simple-server/internal/logger"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
sourceStaticRetryPause = 5 * time.Second
|
||
|
)
|
||
|
|
||
|
type sourceStaticImpl interface {
|
||
|
Log(logger.Level, string, ...interface{})
|
||
|
run(context.Context) error
|
||
|
onSourceAPIDescribe() interface{}
|
||
|
}
|
||
|
|
||
|
type sourceStaticParent interface {
|
||
|
log(logger.Level, string, ...interface{})
|
||
|
onSourceStaticSetReady(req pathSourceStaticSetReadyReq) pathSourceStaticSetReadyRes
|
||
|
onSourceStaticSetNotReady(req pathSourceStaticSetNotReadyReq)
|
||
|
}
|
||
|
|
||
|
// sourceStatic is a static source.
|
||
|
type sourceStatic struct {
|
||
|
ur string
|
||
|
protocol conf.SourceProtocol
|
||
|
anyPortEnable bool
|
||
|
fingerprint string
|
||
|
readTimeout conf.StringDuration
|
||
|
writeTimeout conf.StringDuration
|
||
|
readBufferCount int
|
||
|
wg *sync.WaitGroup
|
||
|
parent sourceStaticParent
|
||
|
|
||
|
impl sourceStaticImpl
|
||
|
ctx context.Context
|
||
|
ctxCancel func()
|
||
|
}
|
||
|
|
||
|
func newSourceStatic(
|
||
|
parentCtx context.Context,
|
||
|
ur string,
|
||
|
protocol conf.SourceProtocol,
|
||
|
anyPortEnable bool,
|
||
|
fingerprint string,
|
||
|
readTimeout conf.StringDuration,
|
||
|
writeTimeout conf.StringDuration,
|
||
|
readBufferCount int,
|
||
|
wg *sync.WaitGroup,
|
||
|
parent sourceStaticParent,
|
||
|
) *sourceStatic {
|
||
|
ctx, ctxCancel := context.WithCancel(parentCtx)
|
||
|
|
||
|
s := &sourceStatic{
|
||
|
ur: ur,
|
||
|
protocol: protocol,
|
||
|
anyPortEnable: anyPortEnable,
|
||
|
fingerprint: fingerprint,
|
||
|
readTimeout: readTimeout,
|
||
|
writeTimeout: writeTimeout,
|
||
|
readBufferCount: readBufferCount,
|
||
|
wg: wg,
|
||
|
parent: parent,
|
||
|
ctx: ctx,
|
||
|
ctxCancel: ctxCancel,
|
||
|
}
|
||
|
|
||
|
switch {
|
||
|
case strings.HasPrefix(s.ur, "rtsp://") ||
|
||
|
strings.HasPrefix(s.ur, "rtsps://"):
|
||
|
s.impl = newRTSPSource(
|
||
|
s.ur,
|
||
|
s.protocol,
|
||
|
s.anyPortEnable,
|
||
|
s.fingerprint,
|
||
|
s.readTimeout,
|
||
|
s.writeTimeout,
|
||
|
s.readBufferCount,
|
||
|
s)
|
||
|
|
||
|
case strings.HasPrefix(s.ur, "rtmp://"):
|
||
|
s.impl = newRTMPSource(
|
||
|
s.ur,
|
||
|
s.readTimeout,
|
||
|
s.writeTimeout,
|
||
|
s)
|
||
|
|
||
|
case strings.HasPrefix(s.ur, "http://") ||
|
||
|
strings.HasPrefix(s.ur, "https://"):
|
||
|
s.impl = newHLSSource(
|
||
|
s.ur,
|
||
|
s.fingerprint,
|
||
|
s)
|
||
|
}
|
||
|
|
||
|
s.impl.Log(logger.Info, "started")
|
||
|
|
||
|
s.wg.Add(1)
|
||
|
go s.run()
|
||
|
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
func (s *sourceStatic) close() {
|
||
|
s.impl.Log(logger.Info, "stopped")
|
||
|
s.ctxCancel()
|
||
|
}
|
||
|
|
||
|
func (s *sourceStatic) log(level logger.Level, format string, args ...interface{}) {
|
||
|
s.parent.log(level, format, args...)
|
||
|
}
|
||
|
|
||
|
func (s *sourceStatic) run() {
|
||
|
defer s.wg.Done()
|
||
|
|
||
|
outer:
|
||
|
for {
|
||
|
innerCtx, innerCtxCancel := context.WithCancel(context.Background())
|
||
|
innerErr := make(chan error)
|
||
|
go func() {
|
||
|
innerErr <- s.impl.run(innerCtx)
|
||
|
}()
|
||
|
|
||
|
select {
|
||
|
case err := <-innerErr:
|
||
|
innerCtxCancel()
|
||
|
s.impl.Log(logger.Info, "ERR: %v", err)
|
||
|
|
||
|
case <-s.ctx.Done():
|
||
|
innerCtxCancel()
|
||
|
<-innerErr
|
||
|
}
|
||
|
|
||
|
select {
|
||
|
case <-time.After(sourceStaticRetryPause):
|
||
|
case <-s.ctx.Done():
|
||
|
break outer
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s.ctxCancel()
|
||
|
}
|
||
|
|
||
|
// onSourceAPIDescribe implements source.
|
||
|
func (s *sourceStatic) onSourceAPIDescribe() interface{} {
|
||
|
return s.impl.onSourceAPIDescribe()
|
||
|
}
|
||
|
|
||
|
// onSourceStaticSetReady is called by a sourceStaticImpl.
|
||
|
func (s *sourceStatic) onSourceStaticSetReady(req pathSourceStaticSetReadyReq) pathSourceStaticSetReadyRes {
|
||
|
req.source = s
|
||
|
return s.parent.onSourceStaticSetReady(req)
|
||
|
}
|
||
|
|
||
|
// onSourceStaticSetNotReady is called by a sourceStaticImpl.
|
||
|
func (s *sourceStatic) onSourceStaticSetNotReady(req pathSourceStaticSetNotReadyReq) {
|
||
|
req.source = s
|
||
|
s.parent.onSourceStaticSetNotReady(req)
|
||
|
}
|