diff --git a/README.md b/README.md index 9584eabf..d45e040c 100644 --- a/README.md +++ b/README.md @@ -553,7 +553,7 @@ This web page can be embedded into another web page by using an iframe: ``` -For more advanced setups, you can create and serve a custom web page by starting from the [source code of the WebRTC publish page](internal/servers/webrtc/publish_index.html). +For more advanced setups, you can create and serve a custom web page by starting from the [source code of the WebRTC publish page](internal/servers/webrtc/publish_index.html). In particular, there's a ready-to-use, standalone JavaScript class for publishing streams with WebRTC, available in [publisher.js](internal/servers/webrtc/publisher.js). ### By device @@ -1104,7 +1104,7 @@ This web page can be embedded into another web page by using an iframe: ``` -For more advanced setups, you can create and serve a custom web page by starting from the [source code of the WebRTC read page](internal/servers/webrtc/read_index.html). +For more advanced setups, you can create and serve a custom web page by starting from the [source code of the WebRTC read page](internal/servers/webrtc/read_index.html). In particular, there's a ready-to-use, standalone JavaScript class for reading streams with WebRTC, available in [reader.js](internal/servers/webrtc/reader.js). Web browsers can also read a stream with the [HLS protocol](#hls). Latency is higher but there are less problems related to connectivity between server and clients, furthermore the server load can be balanced by using a common HTTP CDN (like CloudFront or Cloudflare), and this allows to handle readers in the order of millions. Visit the web page: diff --git a/internal/conf/conf_test.go b/internal/conf/conf_test.go index c555078e..203e1d17 100644 --- a/internal/conf/conf_test.go +++ b/internal/conf/conf_test.go @@ -423,6 +423,14 @@ func TestConfErrors(t *testing.T) { " recordPath: invalid\n", `record path 'invalid' is missing one of the mandatory elements: %path %Y %m %d %H %M %S %f`, }, + { + "invalid record delete after", + "paths:\n" + + " my_path:\n" + + " recordSegmentDuration: 30m\n" + + " recordDeleteAfter: 20m\n", + `'recordDeleteAfter' cannot be lower than 'recordSegmentDuration'`, + }, } { t.Run(ca.name, func(t *testing.T) { tmpf, err := createTempFile([]byte(ca.conf)) diff --git a/internal/conf/path.go b/internal/conf/path.go index 087f49b0..28b2b6ff 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -512,6 +512,10 @@ func (pconf *Path) validate( return fmt.Errorf("maximum segment duration is 1 day") } + if pconf.RecordDeleteAfter != 0 && pconf.RecordDeleteAfter < pconf.RecordSegmentDuration { + return fmt.Errorf("'recordDeleteAfter' cannot be lower than 'recordSegmentDuration'") + } + // Authentication (deprecated) if deprecatedCredentialsMode {