mirror of
https://github.com/bluenviron/mediamtx
synced 2025-03-05 11:57:33 +00:00
parent
4fa6c16c85
commit
c3d9be322d
@ -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
|
||||
|
||||
|
@ -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'")
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user