allow using 'fallback' with static sources (#2606) (#2706)

This commit is contained in:
Alessandro Ros 2023-11-16 23:37:43 +01:00 committed by GitHub
parent 4fa6c16c85
commit c3d9be322d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 67 deletions

View File

@ -210,6 +210,8 @@ components:
type: integer
srtReadPassphrase:
type: string
fallback:
type: string
# Record
record:
@ -246,8 +248,6 @@ components:
# Publisher source
overridePublisher:
type: boolean
fallback:
type: string
srtPublishPassphrase:
type: string

View File

@ -60,6 +60,7 @@ type Path struct {
SourceOnDemandCloseAfter StringDuration `json:"sourceOnDemandCloseAfter"`
MaxReaders int `json:"maxReaders"`
SRTReadPassphrase string `json:"srtReadPassphrase"`
Fallback string `json:"fallback"`
// Record
Record bool `json:"record"`
@ -80,7 +81,6 @@ type Path struct {
// Publisher source
OverridePublisher bool `json:"overridePublisher"`
DisablePublisherOverride *bool `json:"disablePublisherOverride,omitempty"` // deprecated
Fallback string `json:"fallback"`
SRTPublishPassphrase string `json:"srtPublishPassphrase"`
// RTSP source
@ -346,6 +346,19 @@ func (pconf *Path) check(conf *Conf, name string) error {
return fmt.Errorf("invalid 'readRTPassphrase': %v", err)
}
}
if pconf.Fallback != "" {
if strings.HasPrefix(pconf.Fallback, "/") {
err := IsValidPathName(pconf.Fallback[1:])
if err != nil {
return fmt.Errorf("'%s': %s", pconf.Fallback, err)
}
} else {
_, err := base.ParseURL(pconf.Fallback)
if err != nil {
return fmt.Errorf("'%s' is not a valid RTSP URL", pconf.Fallback)
}
}
}
// Authentication
@ -387,23 +400,6 @@ func (pconf *Path) check(conf *Conf, name string) error {
if pconf.DisablePublisherOverride != nil {
pconf.OverridePublisher = !*pconf.DisablePublisherOverride
}
if pconf.Fallback != "" {
if pconf.Source != "publisher" {
return fmt.Errorf("'fallback' can only be used when source is 'publisher'")
}
if strings.HasPrefix(pconf.Fallback, "/") {
err := IsValidPathName(pconf.Fallback[1:])
if err != nil {
return fmt.Errorf("'%s': %s", pconf.Fallback, err)
}
} else {
_, err := base.ParseURL(pconf.Fallback)
if err != nil {
return fmt.Errorf("'%s' is not a valid RTSP URL", pconf.Fallback)
}
}
}
if pconf.SRTPublishPassphrase != "" {
if pconf.Source != "publisher" {
return fmt.Errorf("'srtPublishPassphase' can only be used when source is 'publisher'")

View File

@ -515,3 +515,58 @@ func TestPathRecord(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 2, len(files))
}
func TestPathFallback(t *testing.T) {
for _, ca := range []string{
"absolute",
"relative",
"source",
} {
t.Run(ca, func(t *testing.T) {
var conf string
switch ca {
case "absolute":
conf = "paths:\n" +
" path1:\n" +
" fallback: rtsp://localhost:8554/path2\n" +
" path2:\n"
case "relative":
conf = "paths:\n" +
" path1:\n" +
" fallback: /path2\n" +
" path2:\n"
case "source":
conf = "paths:\n" +
" path1:\n" +
" fallback: /path2\n" +
" source: rtsp://localhost:3333/nonexistent\n" +
" path2:\n"
}
p1, ok := newInstance(conf)
require.Equal(t, true, ok)
defer p1.Close()
source := gortsplib.Client{}
err := source.StartRecording("rtsp://localhost:8554/path2",
&description.Session{Medias: []*description.Media{testMediaH264}})
require.NoError(t, err)
defer source.Close()
u, err := base.ParseURL("rtsp://localhost:8554/path1")
require.NoError(t, err)
dest := gortsplib.Client{}
err = dest.Start(u.Scheme, u.Host)
require.NoError(t, err)
defer dest.Close()
desc, _, err := dest.Describe(u)
require.NoError(t, err)
require.Equal(t, 1, len(desc.Medias))
})
}
}

View File

@ -348,47 +348,3 @@ func TestRTSPServerPublisherOverride(t *testing.T) {
})
}
}
func TestRTSPServerFallback(t *testing.T) {
for _, ca := range []string{
"absolute",
"relative",
} {
t.Run(ca, func(t *testing.T) {
val := func() string {
if ca == "absolute" {
return "rtsp://localhost:8554/path2"
}
return "/path2"
}()
p1, ok := newInstance("rtmp: no\n" +
"hls: no\n" +
"webrtc: no\n" +
"paths:\n" +
" path1:\n" +
" fallback: " + val + "\n" +
" path2:\n")
require.Equal(t, true, ok)
defer p1.Close()
source := gortsplib.Client{}
err := source.StartRecording("rtsp://localhost:8554/path2",
&description.Session{Medias: []*description.Media{testMediaH264}})
require.NoError(t, err)
defer source.Close()
u, err := base.ParseURL("rtsp://localhost:8554/path1")
require.NoError(t, err)
dest := gortsplib.Client{}
err = dest.Start(u.Scheme, u.Host)
require.NoError(t, err)
defer dest.Close()
desc, _, err := dest.Describe(u)
require.NoError(t, err)
require.Equal(t, 1, len(desc.Medias))
})
}
}

View File

@ -285,6 +285,9 @@ pathDefaults:
maxReaders: 0
# SRT encryption passphrase require to read from this path
srtReadPassphrase:
# If the stream is not available, redirect readers to this path.
# It can be can be a relative path (i.e. /otherstream) or an absolute RTSP URL.
fallback:
###############################################
# Default path settings -> Recording
@ -335,9 +338,6 @@ pathDefaults:
# Allow another client to disconnect the current publisher and publish in its place.
overridePublisher: yes
# If no one is publishing, redirect readers to this path.
# It can be can be a relative path (i.e. /otherstream) or an absolute RTSP URL.
fallback:
# SRT encryption passphrase required to publish to this path
srtPublishPassphrase: