From 655e0d0fd6bf7c8d63e59c846f3e664cfc2df715 Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:48:00 +0100 Subject: [PATCH] implement fallback (#104) --- conf/pathconf.go | 12 ++++++++++++ main_test.go | 38 ++++++++++++++++++++++++++++++++++++++ path/path.go | 7 +++++++ rtsp-simple-server.yml | 3 +++ 4 files changed, 60 insertions(+) diff --git a/conf/pathconf.go b/conf/pathconf.go index 3bd8acca..5efa8f37 100644 --- a/conf/pathconf.go +++ b/conf/pathconf.go @@ -24,6 +24,7 @@ type PathConf struct { SourceOnDemandStartTimeout time.Duration `yaml:"sourceOnDemandStartTimeout"` SourceOnDemandCloseAfter time.Duration `yaml:"sourceOnDemandCloseAfter"` SourceRedirect string `yaml:"sourceRedirect"` + Fallback string `yaml:"fallback"` RunOnInit string `yaml:"runOnInit"` RunOnInitRestart bool `yaml:"runOnInitRestart"` RunOnDemand string `yaml:"runOnDemand"` @@ -150,6 +151,17 @@ func (pconf *PathConf) fillAndCheck(name string) error { pconf.SourceOnDemandCloseAfter = 10 * time.Second } + if pconf.Fallback != "" { + u, err := url.Parse(pconf.Fallback) + if err != nil { + return fmt.Errorf("'%s' is not a valid rtsp url", pconf.Fallback) + } + + if u.Scheme != "rtsp" { + return fmt.Errorf("'%s' is not a valid rtsp url", pconf.Fallback) + } + } + if pconf.PublishUser != "" { if !reUserPass.MatchString(pconf.PublishUser) { return fmt.Errorf("publish username contains unsupported characters (supported are %s)", userPassSupportedChars) diff --git a/main_test.go b/main_test.go index 2f7633f7..cba026a3 100644 --- a/main_test.go +++ b/main_test.go @@ -689,6 +689,44 @@ func TestRedirect(t *testing.T) { require.Equal(t, 0, code) } +func TestFallback(t *testing.T) { + p1, err := testProgram("paths:\n" + + " path1:\n" + + " fallback: rtsp://" + ownDockerIp + ":8554/path2\n" + + " path2:\n") + require.NoError(t, err) + defer p1.close() + + time.Sleep(1 * time.Second) + + cnt1, err := newContainer("ffmpeg", "source", []string{ + "-re", + "-stream_loop", "-1", + "-i", "/emptyvideo.ts", + "-c", "copy", + "-f", "rtsp", + "-rtsp_transport", "udp", + "rtsp://" + ownDockerIp + ":8554/path2", + }) + require.NoError(t, err) + defer cnt1.close() + + time.Sleep(1 * time.Second) + + cnt2, err := newContainer("ffmpeg", "dest", []string{ + "-rtsp_transport", "udp", + "-i", "rtsp://" + ownDockerIp + ":8554/path1", + "-vframes", "1", + "-f", "image2", + "-y", "/dev/null", + }) + require.NoError(t, err) + defer cnt2.close() + + code := cnt2.wait() + require.Equal(t, 0, code) +} + func TestRunOnDemand(t *testing.T) { p1, err := testProgram("paths:\n" + " all:\n" + diff --git a/path/path.go b/path/path.go index f8635467..7c325f33 100644 --- a/path/path.go +++ b/path/path.go @@ -612,6 +612,13 @@ func (pa *Path) onClientDescribe(c *client.Client) { return case sourceStateNotReady: + if pa.conf.Fallback != "" { + pa.addClient(c, clientStatePreRemove) + pa.removeClient(c) + c.OnPathDescribeData(nil, pa.conf.Fallback, nil) + return + } + pa.addClient(c, clientStatePreRemove) pa.removeClient(c) c.OnPathDescribeData(nil, "", fmt.Errorf("no one is publishing to path '%s'", pa.name)) diff --git a/rtsp-simple-server.yml b/rtsp-simple-server.yml index 6115a37f..58c8165d 100644 --- a/rtsp-simple-server.yml +++ b/rtsp-simple-server.yml @@ -66,6 +66,9 @@ paths: # redirected to. sourceRedirect: + # fallback url to redirect clients to when nobody is publishing to this path + fallback: + # username required to publish. publishUser: # password required to publish.