update gortsplib (#2126)

This commit is contained in:
Alessandro Ros
2023-07-30 23:39:24 +02:00
committed by GitHub
parent 83484b1e82
commit e3d4856b4f
10 changed files with 81 additions and 83 deletions

2
go.mod
View File

@@ -8,7 +8,7 @@ require (
github.com/alecthomas/kong v0.8.0 github.com/alecthomas/kong v0.8.0
github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87 github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87
github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072 github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072
github.com/bluenviron/gortsplib/v3 v3.9.0 github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230730204034-8b8b52e689d9
github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1

4
go.sum
View File

@@ -12,8 +12,8 @@ github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87 h1:SCAqalLhg
github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI= github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072 h1:pAbC7frXsTMxP7Ck3E50hl7oFeSeD2dgc2lWjmHXztQ= github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072 h1:pAbC7frXsTMxP7Ck3E50hl7oFeSeD2dgc2lWjmHXztQ=
github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072/go.mod h1:rK4b161qErs82QqvBEl84vpi2xhdZBUT0yubXuytZ7E= github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072/go.mod h1:rK4b161qErs82QqvBEl84vpi2xhdZBUT0yubXuytZ7E=
github.com/bluenviron/gortsplib/v3 v3.9.0 h1:aAHV6MhsDtgBF6yKaNBBCdvtSpLB8ne4kyUfLQlN7nM= github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230730204034-8b8b52e689d9 h1:QBdUlT/taEG0b8dxguJ6GYT7r6vJFRhvwlhs1LGWYlQ=
github.com/bluenviron/gortsplib/v3 v3.9.0/go.mod h1:5h3Zu7jkzwDknYrf+89q2saab//oioKgM9mgvBEX3pg= github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230730204034-8b8b52e689d9/go.mod h1:vBmCYjtox2pXWSvU+r9ROpEbwSOhh5lVWd+t9Sj8glc=
github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda h1:+ungCWRNDjsy/CVL1l/UjAj4vYL4+NIJQoJJWbR3Xw8= github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda h1:+ungCWRNDjsy/CVL1l/UjAj4vYL4+NIJQoJJWbR3Xw8=
github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda/go.mod h1:tfk0qGPhqnOxVCrElu8ct3LKQn6Cj4Tpu3zbbJBTKj4= github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda/go.mod h1:tfk0qGPhqnOxVCrElu8ct3LKQn6Cj4Tpu3zbbJBTKj4=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=

View File

@@ -115,7 +115,7 @@ type pathReaderAddReq struct {
res chan pathReaderSetupPlayRes res chan pathReaderSetupPlayRes
} }
type pathPublisherAnnounceRes struct { type pathPublisherAddRes struct {
path *path path *path
err error err error
} }
@@ -125,7 +125,7 @@ type pathPublisherAddReq struct {
pathName string pathName string
skipAuth bool skipAuth bool
credentials authCredentials credentials authCredentials
res chan pathPublisherAnnounceRes res chan pathPublisherAddRes
} }
type pathPublisherRecordRes struct { type pathPublisherRecordRes struct {
@@ -743,7 +743,7 @@ func (pa *path) handlePublisherRemove(req pathPublisherRemoveReq) {
func (pa *path) handlePublisherAdd(req pathPublisherAddReq) { func (pa *path) handlePublisherAdd(req pathPublisherAddReq) {
if pa.conf.Source != "publisher" { if pa.conf.Source != "publisher" {
req.res <- pathPublisherAnnounceRes{ req.res <- pathPublisherAddRes{
err: fmt.Errorf("can't publish to path '%s' since 'source' is not 'publisher'", pa.name), err: fmt.Errorf("can't publish to path '%s' since 'source' is not 'publisher'", pa.name),
} }
return return
@@ -751,7 +751,7 @@ func (pa *path) handlePublisherAdd(req pathPublisherAddReq) {
if pa.source != nil { if pa.source != nil {
if pa.conf.DisablePublisherOverride { if pa.conf.DisablePublisherOverride {
req.res <- pathPublisherAnnounceRes{err: fmt.Errorf("someone is already publishing to path '%s'", pa.name)} req.res <- pathPublisherAddRes{err: fmt.Errorf("someone is already publishing to path '%s'", pa.name)}
return return
} }
@@ -762,7 +762,7 @@ func (pa *path) handlePublisherAdd(req pathPublisherAddReq) {
pa.source = req.author pa.source = req.author
req.res <- pathPublisherAnnounceRes{path: pa} req.res <- pathPublisherAddRes{path: pa}
} }
func (pa *path) handlePublisherStart(req pathPublisherStartReq) { func (pa *path) handlePublisherStart(req pathPublisherStartReq) {
@@ -973,12 +973,12 @@ func (pa *path) publisherRemove(req pathPublisherRemoveReq) {
} }
// publisherAdd is called by a publisher through pathManager. // publisherAdd is called by a publisher through pathManager.
func (pa *path) publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes { func (pa *path) publisherAdd(req pathPublisherAddReq) pathPublisherAddRes {
select { select {
case pa.chPublisherAdd <- req: case pa.chPublisherAdd <- req:
return <-req.res return <-req.res
case <-pa.ctx.Done(): case <-pa.ctx.Done():
return pathPublisherAnnounceRes{err: fmt.Errorf("terminated")} return pathPublisherAddRes{err: fmt.Errorf("terminated")}
} }
} }

View File

@@ -289,14 +289,14 @@ outer:
case req := <-pm.chPublisherAdd: case req := <-pm.chPublisherAdd:
pathConfName, pathConf, pathMatches, err := getConfForPath(pm.pathConfs, req.pathName) pathConfName, pathConf, pathMatches, err := getConfForPath(pm.pathConfs, req.pathName)
if err != nil { if err != nil {
req.res <- pathPublisherAnnounceRes{err: err} req.res <- pathPublisherAddRes{err: err}
continue continue
} }
if !req.skipAuth { if !req.skipAuth {
err = doAuthentication(pm.externalAuthenticationURL, pm.authMethods, req.pathName, pathConf, true, req.credentials) err = doAuthentication(pm.externalAuthenticationURL, pm.authMethods, req.pathName, pathConf, true, req.credentials)
if err != nil { if err != nil {
req.res <- pathPublisherAnnounceRes{err: err} req.res <- pathPublisherAddRes{err: err}
continue continue
} }
} }
@@ -306,7 +306,7 @@ outer:
pm.createPath(pathConfName, pathConf, req.pathName, pathMatches) pm.createPath(pathConfName, pathConf, req.pathName, pathMatches)
} }
req.res <- pathPublisherAnnounceRes{path: pm.paths[req.pathName]} req.res <- pathPublisherAddRes{path: pm.paths[req.pathName]}
case s := <-pm.chHLSManagerSet: case s := <-pm.chHLSManagerSet:
pm.hlsManager = s pm.hlsManager = s
@@ -449,8 +449,8 @@ func (pm *pathManager) describe(req pathDescribeReq) pathDescribeRes {
} }
// publisherAnnounce is called by a publisher. // publisherAnnounce is called by a publisher.
func (pm *pathManager) publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes { func (pm *pathManager) publisherAdd(req pathPublisherAddReq) pathPublisherAddRes {
req.res = make(chan pathPublisherAnnounceRes) req.res = make(chan pathPublisherAddRes)
select { select {
case pm.chPublisherAdd <- req: case pm.chPublisherAdd <- req:
res := <-req.res res := <-req.res
@@ -461,7 +461,7 @@ func (pm *pathManager) publisherAdd(req pathPublisherAddReq) pathPublisherAnnoun
return res.path.publisherAdd(req) return res.path.publisherAdd(req)
case <-pm.ctx.Done(): case <-pm.ctx.Done():
return pathPublisherAnnounceRes{err: fmt.Errorf("terminated")} return pathPublisherAddRes{err: fmt.Errorf("terminated")}
} }
} }

View File

@@ -48,7 +48,7 @@ const (
type rtmpConnPathManager interface { type rtmpConnPathManager interface {
readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes
publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes publisherAdd(req pathPublisherAddReq) pathPublisherAddRes
} }
type rtmpConnParent interface { type rtmpConnParent interface {

View File

@@ -137,7 +137,13 @@ func (c *rtspConn) onDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx,
ctx.Path = ctx.Path[1:] ctx.Path = ctx.Path[1:]
if c.authNonce == "" { if c.authNonce == "" {
c.authNonce = auth.GenerateNonce() var err error
c.authNonce, err = auth.GenerateNonce()
if err != nil {
return &base.Response{
StatusCode: base.StatusInternalServerError,
}, nil, err
}
} }
res := c.pathManager.describe(pathDescribeReq{ res := c.pathManager.describe(pathDescribeReq{

View File

@@ -21,7 +21,7 @@ import (
) )
type rtspSessionPathManager interface { type rtspSessionPathManager interface {
publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes publisherAdd(req pathPublisherAddReq) pathPublisherAddRes
readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes
} }
@@ -122,7 +122,13 @@ func (s *rtspSession) onAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnno
ctx.Path = ctx.Path[1:] ctx.Path = ctx.Path[1:]
if c.authNonce == "" { if c.authNonce == "" {
c.authNonce = auth.GenerateNonce() var err error
c.authNonce, err = auth.GenerateNonce()
if err != nil {
return &base.Response{
StatusCode: base.StatusInternalServerError,
}, err
}
} }
res := s.pathManager.publisherAdd(pathPublisherAddReq{ res := s.pathManager.publisherAdd(pathPublisherAddReq{
@@ -201,7 +207,13 @@ func (s *rtspSession) onSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCt
} }
if c.authNonce == "" { if c.authNonce == "" {
c.authNonce = auth.GenerateNonce() var err error
c.authNonce, err = auth.GenerateNonce()
if err != nil {
return &base.Response{
StatusCode: base.StatusInternalServerError,
}, nil, err
}
} }
res := s.pathManager.readerAdd(pathReaderAddReq{ res := s.pathManager.readerAdd(pathReaderAddReq{

View File

@@ -2,11 +2,6 @@ package core
import ( import (
"context" "context"
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"fmt"
"strings"
"time" "time"
"github.com/bluenviron/gortsplib/v3" "github.com/bluenviron/gortsplib/v3"
@@ -19,37 +14,6 @@ import (
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
) )
type rtspSourceParent interface {
logger.Writer
sourceStaticImplSetReady(req pathSourceStaticSetReadyReq) pathSourceStaticSetReadyRes
sourceStaticImplSetNotReady(req pathSourceStaticSetNotReadyReq)
}
type rtspSource struct {
readTimeout conf.StringDuration
writeTimeout conf.StringDuration
readBufferCount int
parent rtspSourceParent
}
func newRTSPSource(
readTimeout conf.StringDuration,
writeTimeout conf.StringDuration,
readBufferCount int,
parent rtspSourceParent,
) *rtspSource {
return &rtspSource{
readTimeout: readTimeout,
writeTimeout: writeTimeout,
readBufferCount: readBufferCount,
parent: parent,
}
}
func (s *rtspSource) Log(level logger.Level, format string, args ...interface{}) {
s.parent.Log(level, "[rtsp source] "+format, args...)
}
func createRangeHeader(cnf *conf.PathConf) (*headers.Range, error) { func createRangeHeader(cnf *conf.PathConf) (*headers.Range, error) {
switch cnf.RtspRangeType { switch cnf.RtspRangeType {
case conf.RtspRangeTypeClock: case conf.RtspRangeTypeClock:
@@ -95,33 +59,44 @@ func createRangeHeader(cnf *conf.PathConf) (*headers.Range, error) {
} }
} }
type rtspSourceParent interface {
logger.Writer
sourceStaticImplSetReady(req pathSourceStaticSetReadyReq) pathSourceStaticSetReadyRes
sourceStaticImplSetNotReady(req pathSourceStaticSetNotReadyReq)
}
type rtspSource struct {
readTimeout conf.StringDuration
writeTimeout conf.StringDuration
readBufferCount int
parent rtspSourceParent
}
func newRTSPSource(
readTimeout conf.StringDuration,
writeTimeout conf.StringDuration,
readBufferCount int,
parent rtspSourceParent,
) *rtspSource {
return &rtspSource{
readTimeout: readTimeout,
writeTimeout: writeTimeout,
readBufferCount: readBufferCount,
parent: parent,
}
}
func (s *rtspSource) Log(level logger.Level, format string, args ...interface{}) {
s.parent.Log(level, "[rtsp source] "+format, args...)
}
// run implements sourceStaticImpl. // run implements sourceStaticImpl.
func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan *conf.PathConf) error { func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan *conf.PathConf) error {
s.Log(logger.Debug, "connecting") s.Log(logger.Debug, "connecting")
var tlsConfig *tls.Config
if cnf.SourceFingerprint != "" {
tlsConfig = &tls.Config{
InsecureSkipVerify: true,
VerifyConnection: func(cs tls.ConnectionState) error {
h := sha256.New()
h.Write(cs.PeerCertificates[0].Raw)
hstr := hex.EncodeToString(h.Sum(nil))
fingerprintLower := strings.ToLower(cnf.SourceFingerprint)
if hstr != fingerprintLower {
return fmt.Errorf("server fingerprint do not match: expected %s, got %s",
fingerprintLower, hstr)
}
return nil
},
}
}
c := &gortsplib.Client{ c := &gortsplib.Client{
Transport: cnf.SourceProtocol.Transport, Transport: cnf.SourceProtocol.Transport,
TLSConfig: tlsConfig, TLSConfig: tlsConfigForFingerprint(cnf.SourceFingerprint),
ReadTimeout: time.Duration(s.readTimeout), ReadTimeout: time.Duration(s.readTimeout),
WriteTimeout: time.Duration(s.writeTimeout), WriteTimeout: time.Duration(s.writeTimeout),
ReadBufferCount: s.readBufferCount, ReadBufferCount: s.readBufferCount,

View File

@@ -43,7 +43,9 @@ func TestRTSPSource(t *testing.T) {
t.Run(source, func(t *testing.T) { t.Run(source, func(t *testing.T) {
medi := testMediaH264 medi := testMediaH264
stream := gortsplib.NewServerStream(media.Medias{medi}) stream := gortsplib.NewServerStream(media.Medias{medi})
nonce := auth.GenerateNonce()
nonce, err := auth.GenerateNonce()
require.NoError(t, err)
s := gortsplib.Server{ s := gortsplib.Server{
Handler: &testServer{ Handler: &testServer{
@@ -112,7 +114,7 @@ func TestRTSPSource(t *testing.T) {
s.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}} s.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
} }
err := s.Start() err = s.Start()
require.NoError(t, err) require.NoError(t, err)
defer s.Wait() defer s.Wait()
defer s.Close() defer s.Close()
@@ -167,7 +169,10 @@ func TestRTSPSource(t *testing.T) {
func TestRTSPSourceNoPassword(t *testing.T) { func TestRTSPSourceNoPassword(t *testing.T) {
stream := gortsplib.NewServerStream(media.Medias{testMediaH264}) stream := gortsplib.NewServerStream(media.Medias{testMediaH264})
nonce := auth.GenerateNonce()
nonce, err := auth.GenerateNonce()
require.NoError(t, err)
done := make(chan struct{}) done := make(chan struct{})
s := gortsplib.Server{ s := gortsplib.Server{
@@ -201,7 +206,7 @@ func TestRTSPSourceNoPassword(t *testing.T) {
}, },
RTSPAddress: "127.0.0.1:8555", RTSPAddress: "127.0.0.1:8555",
} }
err := s.Start() err = s.Start()
require.NoError(t, err) require.NoError(t, err)
defer s.Wait() defer s.Wait()
defer s.Close() defer s.Close()

View File

@@ -131,7 +131,7 @@ func gatherIncomingTracks(
} }
type webRTCSessionPathManager interface { type webRTCSessionPathManager interface {
publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes publisherAdd(req pathPublisherAddReq) pathPublisherAddRes
readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes
} }