Browse Source

support relative fallback paths (#201)

pull/235/head v0.14.1
aler9 5 years ago
parent
commit
22ab4d489e
  1. 4
      README.md
  2. 20
      internal/conf/path.go
  3. 15
      internal/path/path.go
  4. 70
      main_test.go
  5. 9
      rtsp-simple-server.yml

4
README.md

@ -414,12 +414,12 @@ paths: @@ -414,12 +414,12 @@ paths:
### Fallback stream
If no one is publishing to the server, readers can be redirected to a fallback URL that is serving a fallback stream:
If no one is publishing to the server, readers can be redirected to a fallback path or URL that is serving a fallback stream:
```yml
paths:
withfallback:
fallback: rtsp://otherurl/otherpath
fallback: /otherpath
```
### Start on boot with systemd

20
internal/conf/path.go

@ -198,8 +198,8 @@ func (pconf *PathConf) fillAndCheck(name string) error { @@ -198,8 +198,8 @@ func (pconf *PathConf) fillAndCheck(name string) error {
}
if pconf.SourceOnDemand {
if pconf.Source != "record" {
return fmt.Errorf("'sourceOnDemand' is useless when source is not 'record', since the stream is not provided by a publisher, but by a fixed source")
if pconf.Source == "record" {
return fmt.Errorf("'sourceOnDemand' is useless when source is 'record'")
}
}
@ -212,9 +212,17 @@ func (pconf *PathConf) fillAndCheck(name string) error { @@ -212,9 +212,17 @@ func (pconf *PathConf) fillAndCheck(name string) error {
}
if pconf.Fallback != "" {
_, err := base.ParseURL(pconf.Fallback)
if err != nil {
return fmt.Errorf("'%s' is not a valid RTSP url", pconf.Fallback)
if strings.HasPrefix(pconf.Fallback, "/") {
err := CheckPathName(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)
}
}
}
@ -223,7 +231,7 @@ func (pconf *PathConf) fillAndCheck(name string) error { @@ -223,7 +231,7 @@ func (pconf *PathConf) fillAndCheck(name string) error {
}
if pconf.PublishUser != "" {
if pconf.Source != "record" {
return fmt.Errorf("'publishUser' is useless when source is not 'record', since the stream is not provided by a publisher, but by a fixed source")
return fmt.Errorf("'publishUser' is useless when source is not 'record'")
}
if !strings.HasPrefix(pconf.PublishUser, "sha256:") && !reUserPass.MatchString(pconf.PublishUser) {

15
internal/path/path.go

@ -9,6 +9,7 @@ import ( @@ -9,6 +9,7 @@ import (
"time"
"github.com/aler9/gortsplib"
"github.com/aler9/gortsplib/pkg/base"
"github.com/aler9/rtsp-simple-server/internal/client"
"github.com/aler9/rtsp-simple-server/internal/clientrtsp"
@ -598,7 +599,19 @@ func (pa *Path) onClientDescribe(req client.DescribeReq) { @@ -598,7 +599,19 @@ func (pa *Path) onClientDescribe(req client.DescribeReq) {
case sourceStateNotReady:
if pa.conf.Fallback != "" {
req.Res <- client.DescribeRes{nil, pa.conf.Fallback, nil} //nolint:govet
fallbackURL := func() string {
if strings.HasPrefix(pa.conf.Fallback, "/") {
ur := base.URL{
Scheme: req.Req.URL.Scheme,
User: req.Req.URL.User,
Host: req.Req.URL.Host,
Path: pa.conf.Fallback,
}
return ur.String()
}
return pa.conf.Fallback
}()
req.Res <- client.DescribeRes{nil, fallbackURL, nil} //nolint:govet
return
}

70
main_test.go

@ -851,37 +851,51 @@ func TestRedirect(t *testing.T) { @@ -851,37 +851,51 @@ func TestRedirect(t *testing.T) {
}
func TestFallback(t *testing.T) {
p1, ok := testProgram("paths:\n" +
" path1:\n" +
" fallback: rtsp://" + ownDockerIP + ":8554/path2\n" +
" path2:\n")
require.Equal(t, true, ok)
defer p1.close()
for _, ca := range []string{
"absolute",
"relative",
} {
t.Run(ca, func(t *testing.T) {
val := func() string {
if ca == "absolute" {
return "rtsp://" + ownDockerIP + ":8554/path2"
}
return "/path2"
}()
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()
p1, ok := testProgram("paths:\n" +
" path1:\n" +
" fallback: " + val + "\n" +
" path2:\n")
require.Equal(t, true, ok)
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()
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()
require.Equal(t, 0, cnt2.wait())
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()
require.Equal(t, 0, cnt2.wait())
})
}
}
func TestRTMP(t *testing.T) {

9
rtsp-simple-server.yml

@ -86,12 +86,12 @@ paths: @@ -86,12 +86,12 @@ paths:
# * redirect -> the stream is provided by another path or server
source: record
# if the source is an RTSP url, this is the protocol that will be used to
# if the source is an RTSP URL, this is the protocol that will be used to
# pull the stream. available options are "automatic", "udp", "tcp".
# the tcp protocol can help to overcome the error "no UDP packets received recently".
sourceProtocol: automatic
# if the source is an RTSP or RTMP url, it will be pulled only when at least
# if the source is an RTSP or RTMP URL, it will be pulled only when at least
# one reader is connected, saving bandwidth.
sourceOnDemand: no
# if sourceOnDemand is "yes", readers will be put on hold until the source is
@ -101,11 +101,12 @@ paths: @@ -101,11 +101,12 @@ paths:
# readers connected and this amount of time has passed.
sourceOnDemandCloseAfter: 10s
# if the source is "redirect", this is the RTSP url which clients will be
# if the source is "redirect", this is the RTSP URL which clients will be
# redirected to.
sourceRedirect:
# fallback url to redirect clients to when nobody is publishing to this path.
# 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.
fallback:
# username required to publish.

Loading…
Cancel
Save