From 0048a0158461181926d187c5866d97d7af31d74a Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Mon, 22 Mar 2021 22:15:22 +0100 Subject: [PATCH] add parameter disablePublisherOverride to disable publisher override (#230) --- internal/conf/path.go | 1 + internal/path/path.go | 5 ++ main_clientrtsp_test.go | 110 ++++++++++++++++++++++++++++------------ rtsp-simple-server.yml | 8 ++- 4 files changed, 90 insertions(+), 34 deletions(-) diff --git a/internal/conf/path.go b/internal/conf/path.go index b99487f7..880f3800 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -74,6 +74,7 @@ type PathConf struct { SourceOnDemandStartTimeout time.Duration `yaml:"sourceOnDemandStartTimeout"` SourceOnDemandCloseAfter time.Duration `yaml:"sourceOnDemandCloseAfter"` SourceRedirect string `yaml:"sourceRedirect"` + DisablePublisherOverride bool `yaml:"disablePublisherOverride"` Fallback string `yaml:"fallback"` RunOnInit string `yaml:"runOnInit"` RunOnInitRestart bool `yaml:"runOnInitRestart"` diff --git a/internal/path/path.go b/internal/path/path.go index 84f1b6fc..acb9dc20 100644 --- a/internal/path/path.go +++ b/internal/path/path.go @@ -689,6 +689,11 @@ func (pa *Path) onClientAnnounce(req client.AnnounceReq) { } if pa.source != nil { + if pa.conf.DisablePublisherOverride { + req.Res <- client.AnnounceRes{nil, fmt.Errorf("another client is already publishing on path '%s'", pa.name)} //nolint:govet + return + } + pa.Log(logger.Info, "disconnecting existing publisher") curPublisher := pa.source.(client.Client) pa.removeClient(curPublisher) diff --git a/main_clientrtsp_test.go b/main_clientrtsp_test.go index 10b84c61..83edec01 100644 --- a/main_clientrtsp_test.go +++ b/main_clientrtsp_test.go @@ -448,45 +448,91 @@ func TestClientRTSPAutomaticProtocol(t *testing.T) { } func TestClientRTSPPublisherOverride(t *testing.T) { - p, ok := testProgram("rtmpDisable: yes\n") - require.Equal(t, true, ok) - defer p.close() + t.Run("enabled", func(t *testing.T) { + p, ok := testProgram("rtmpDisable: yes\n") + require.Equal(t, true, ok) + defer p.close() - source1, err := newContainer("ffmpeg", "source1", []string{ - "-re", - "-stream_loop", "-1", - "-i", "emptyvideo.mkv", - "-c", "copy", - "-f", "rtsp", - "rtsp://" + ownDockerIP + ":8554/teststream", - }) - require.NoError(t, err) - defer source1.close() + source1, err := newContainer("ffmpeg", "source1", []string{ + "-re", + "-stream_loop", "-1", + "-i", "emptyvideo.mkv", + "-c", "copy", + "-f", "rtsp", + "rtsp://" + ownDockerIP + ":8554/teststream", + }) + require.NoError(t, err) + defer source1.close() - time.Sleep(1 * time.Second) + time.Sleep(1 * time.Second) - source2, err := newContainer("ffmpeg", "source2", []string{ - "-re", - "-stream_loop", "-1", - "-i", "emptyvideo.mkv", - "-c", "copy", - "-f", "rtsp", - "rtsp://" + ownDockerIP + ":8554/teststream", + source2, err := newContainer("ffmpeg", "source2", []string{ + "-re", + "-stream_loop", "-1", + "-i", "emptyvideo.mkv", + "-c", "copy", + "-f", "rtsp", + "rtsp://" + ownDockerIP + ":8554/teststream", + }) + require.NoError(t, err) + defer source2.close() + + time.Sleep(1 * time.Second) + + dest, err := newContainer("ffmpeg", "dest", []string{ + "-i", "rtsp://" + ownDockerIP + ":8554/teststream", + "-vframes", "1", + "-f", "image2", + "-y", "/dev/null", + }) + require.NoError(t, err) + defer dest.close() + require.Equal(t, 0, dest.wait()) }) - require.NoError(t, err) - defer source2.close() - time.Sleep(1 * time.Second) + t.Run("disabled", func(t *testing.T) { + p, ok := testProgram("rtmpDisable: yes\n" + + "paths:\n" + + " all:\n" + + " disablePublisherOverride: yes\n") + require.Equal(t, true, ok) + defer p.close() - dest, err := newContainer("ffmpeg", "dest", []string{ - "-i", "rtsp://" + ownDockerIP + ":8554/teststream", - "-vframes", "1", - "-f", "image2", - "-y", "/dev/null", + source1, err := newContainer("ffmpeg", "source1", []string{ + "-re", + "-stream_loop", "-1", + "-i", "emptyvideo.mkv", + "-c", "copy", + "-f", "rtsp", + "rtsp://" + ownDockerIP + ":8554/teststream", + }) + require.NoError(t, err) + defer source1.close() + + time.Sleep(1 * time.Second) + + source2, err := newContainer("ffmpeg", "source2", []string{ + "-re", + "-stream_loop", "-1", + "-i", "emptyvideo.mkv", + "-c", "copy", + "-f", "rtsp", + "rtsp://" + ownDockerIP + ":8554/teststream", + }) + require.NoError(t, err) + defer source2.close() + require.NotEqual(t, 0, source2.wait()) + + dest, err := newContainer("ffmpeg", "dest", []string{ + "-i", "rtsp://" + ownDockerIP + ":8554/teststream", + "-vframes", "1", + "-f", "image2", + "-y", "/dev/null", + }) + require.NoError(t, err) + defer dest.close() + require.Equal(t, 0, dest.wait()) }) - require.NoError(t, err) - defer dest.close() - require.Equal(t, 0, dest.wait()) } func TestClientRTSPNonCompliantFrameSize(t *testing.T) { diff --git a/rtsp-simple-server.yml b/rtsp-simple-server.yml index 0f0f3551..b47de286 100644 --- a/rtsp-simple-server.yml +++ b/rtsp-simple-server.yml @@ -114,8 +114,12 @@ paths: # redirected to. sourceRedirect: - # fallback stream to redirect clients to when nobody is publishing to this path. - # this can be a relative path (i.e. /otherstream) or an absolute RTSP URL. + # if the source is "record" and a client is publishing, do not allow another + # client to disconnect the former and publish in its place. + disablePublisherOverride: no + + # if the source is "record" and 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: # username required to publish.