enable rtmp by default; add parameters to disable rtsp and rtmp

This commit is contained in:
aler9 2021-03-10 20:19:43 +01:00
parent 09cbeae60f
commit f19e23eaa5
5 changed files with 78 additions and 52 deletions

View File

@ -282,13 +282,11 @@ paths:
### RTMP protocol ### RTMP protocol
RTMP is a protocol that is used to read and publish streams, but is less versatile and less efficient than RTSP (doesn't support UDP, encryption, most RTSP codecs, feedback mechanism). If there is need of publishing or reading streams from a software that supports only RTMP (for instance, OBS Studio and DJI drones), it's possible to turn on a RTMP listener: RTMP is a protocol that is used to read and publish streams, but is less versatile and less efficient than RTSP (doesn't support UDP, encryption, doesn't support most RTSP codecs, doesn't support feedback mechanism). It is used when there's need of publishing or reading streams from a software that supports only RTMP (for instance, OBS Studio and DJI drones).
```yml At the moment, only the H264 and AAC codecs can be used with the RTMP listener.
rtmpEnable: yes
```
Streams can then be published or read with the RTMP protocol, for instance with _FFmpeg_: Streams can be published or read with the RTMP protocol, for instance with _FFmpeg_:
``` ```
ffmpeg -re -stream_loop -1 -i file.ts -c copy -f flv rtmp://localhost/mystream ffmpeg -re -stream_loop -1 -i file.ts -c copy -f flv rtmp://localhost/mystream
@ -306,8 +304,6 @@ Credentials can be provided by appending to the URL the `user` and `pass` parame
ffmpeg -re -stream_loop -1 -i file.ts -c copy -f flv rtmp://localhost:8554/mystream?user=myuser&pass=mypass ffmpeg -re -stream_loop -1 -i file.ts -c copy -f flv rtmp://localhost:8554/mystream?user=myuser&pass=mypass
``` ```
At the moment the RTMP listener supports only the H264 and AAC codecs.
### Publish a webcam ### Publish a webcam
Edit `rtsp-simple-server.yml` and replace everything inside section `paths` with the following content: Edit `rtsp-simple-server.yml` and replace everything inside section `paths` with the following content:

View File

@ -63,6 +63,7 @@ type Conf struct {
RunOnConnectRestart bool `yaml:"runOnConnectRestart"` RunOnConnectRestart bool `yaml:"runOnConnectRestart"`
// rtsp // rtsp
RTSPDisable bool `yaml:"rtspDisable"`
Protocols []string `yaml:"protocols"` Protocols []string `yaml:"protocols"`
ProtocolsParsed map[gortsplib.StreamProtocol]struct{} `yaml:"-" json:"-"` ProtocolsParsed map[gortsplib.StreamProtocol]struct{} `yaml:"-" json:"-"`
Encryption string `yaml:"encryption"` Encryption string `yaml:"encryption"`
@ -78,8 +79,8 @@ type Conf struct {
ReadBufferSize int `yaml:"readBufferSize"` ReadBufferSize int `yaml:"readBufferSize"`
// rtmp // rtmp
RTMPEnable bool `yaml:"rtmpEnable"` RTMPDisable bool `yaml:"rtmpDisable"`
RTMPPort int `yaml:"rtmpPort"` RTMPPort int `yaml:"rtmpPort"`
// path // path
Paths map[string]*PathConf `yaml:"paths"` Paths map[string]*PathConf `yaml:"paths"`

16
main.go
View File

@ -183,8 +183,9 @@ func (p *program) createResources(initial bool) error {
} }
} }
if p.conf.EncryptionParsed == conf.EncryptionNo || if !p.conf.RTSPDisable &&
p.conf.EncryptionParsed == conf.EncryptionOptional { (p.conf.EncryptionParsed == conf.EncryptionNo ||
p.conf.EncryptionParsed == conf.EncryptionOptional) {
if p.serverRTSPPlain == nil { if p.serverRTSPPlain == nil {
_, useUDP := p.conf.ProtocolsParsed[gortsplib.StreamProtocolUDP] _, useUDP := p.conf.ProtocolsParsed[gortsplib.StreamProtocolUDP]
p.serverRTSPPlain, err = serverrtsp.New( p.serverRTSPPlain, err = serverrtsp.New(
@ -207,8 +208,9 @@ func (p *program) createResources(initial bool) error {
} }
} }
if p.conf.EncryptionParsed == conf.EncryptionStrict || if !p.conf.RTSPDisable &&
p.conf.EncryptionParsed == conf.EncryptionOptional { (p.conf.EncryptionParsed == conf.EncryptionStrict ||
p.conf.EncryptionParsed == conf.EncryptionOptional) {
if p.serverRTSPTLS == nil { if p.serverRTSPTLS == nil {
p.serverRTSPTLS, err = serverrtsp.New( p.serverRTSPTLS, err = serverrtsp.New(
p.conf.ListenIP, p.conf.ListenIP,
@ -230,7 +232,7 @@ func (p *program) createResources(initial bool) error {
} }
} }
if p.conf.RTMPEnable { if !p.conf.RTMPDisable {
if p.serverRTMP == nil { if p.serverRTMP == nil {
p.serverRTMP, err = serverrtmp.New( p.serverRTMP, err = serverrtmp.New(
p.conf.ListenIP, p.conf.ListenIP,
@ -299,6 +301,7 @@ func (p *program) closeResources(newConf *conf.Conf) {
closeServerPlain := false closeServerPlain := false
if newConf == nil || if newConf == nil ||
newConf.RTSPDisable != p.conf.RTSPDisable ||
newConf.EncryptionParsed != p.conf.EncryptionParsed || newConf.EncryptionParsed != p.conf.EncryptionParsed ||
newConf.ListenIP != p.conf.ListenIP || newConf.ListenIP != p.conf.ListenIP ||
newConf.RTSPPort != p.conf.RTSPPort || newConf.RTSPPort != p.conf.RTSPPort ||
@ -313,6 +316,7 @@ func (p *program) closeResources(newConf *conf.Conf) {
closeServerTLS := false closeServerTLS := false
if newConf == nil || if newConf == nil ||
newConf.RTSPDisable != p.conf.RTSPDisable ||
newConf.EncryptionParsed != p.conf.EncryptionParsed || newConf.EncryptionParsed != p.conf.EncryptionParsed ||
newConf.ListenIP != p.conf.ListenIP || newConf.ListenIP != p.conf.ListenIP ||
newConf.RTSPSPort != p.conf.RTSPSPort || newConf.RTSPSPort != p.conf.RTSPSPort ||
@ -326,7 +330,7 @@ func (p *program) closeResources(newConf *conf.Conf) {
closeServerRTMP := false closeServerRTMP := false
if newConf == nil || if newConf == nil ||
newConf.EncryptionParsed != p.conf.EncryptionParsed || newConf.RTMPDisable != p.conf.RTMPDisable ||
newConf.ListenIP != p.conf.ListenIP || newConf.ListenIP != p.conf.ListenIP ||
newConf.RTMPPort != p.conf.RTMPPort || newConf.RTMPPort != p.conf.RTMPPort ||
newConf.ReadTimeout != p.conf.ReadTimeout { newConf.ReadTimeout != p.conf.ReadTimeout {

View File

@ -223,7 +223,8 @@ func TestRTSPPublishRead(t *testing.T) {
proto = "rtsp" proto = "rtsp"
port = "8554" port = "8554"
p, ok := testProgram("readTimeout: 20s") p, ok := testProgram("rtmpDisable: yes\n" +
"readTimeout: 20s\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -239,7 +240,8 @@ func TestRTSPPublishRead(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer os.Remove(serverKeyFpath) defer os.Remove(serverKeyFpath)
p, ok := testProgram("readTimeout: 20s\n" + p, ok := testProgram("rtmpDisable: yes\n" +
"readTimeout: 20s\n" +
"protocols: [tcp]\n" + "protocols: [tcp]\n" +
"encryption: yes\n" + "encryption: yes\n" +
"serverCert: " + serverCertFpath + "\n" + "serverCert: " + serverCertFpath + "\n" +
@ -317,7 +319,8 @@ func TestRTSPPublishRead(t *testing.T) {
func TestRTSPAuth(t *testing.T) { func TestRTSPAuth(t *testing.T) {
t.Run("publish", func(t *testing.T) { t.Run("publish", func(t *testing.T) {
p, ok := testProgram("paths:\n" + p, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" all:\n" + " all:\n" +
" publishUser: testuser\n" + " publishUser: testuser\n" +
" publishPass: test!$()*+.;<=>[]^_-{}\n" + " publishPass: test!$()*+.;<=>[]^_-{}\n" +
@ -356,7 +359,8 @@ func TestRTSPAuth(t *testing.T) {
"vlc", "vlc",
} { } {
t.Run("read_"+soft, func(t *testing.T) { t.Run("read_"+soft, func(t *testing.T) {
p, ok := testProgram("paths:\n" + p, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" all:\n" + " all:\n" +
" readUser: testuser\n" + " readUser: testuser\n" +
" readPass: test!$()*+.;<=>[]^_-{}\n" + " readPass: test!$()*+.;<=>[]^_-{}\n" +
@ -402,7 +406,8 @@ func TestRTSPAuth(t *testing.T) {
} }
t.Run("hashed", func(t *testing.T) { t.Run("hashed", func(t *testing.T) {
p, ok := testProgram("paths:\n" + p, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" all:\n" + " all:\n" +
" readUser: sha256:rl3rgi4NcZkpAEcacZnQ2VuOfJ0FxAqCRaKB/SwdZoQ=\n" + " readUser: sha256:rl3rgi4NcZkpAEcacZnQ2VuOfJ0FxAqCRaKB/SwdZoQ=\n" +
" readPass: sha256:E9JJ8stBJ7QM+nV4ZoUCeHk/gU3tPFh/5YieiJp6n2w=\n") " readPass: sha256:E9JJ8stBJ7QM+nV4ZoUCeHk/gU3tPFh/5YieiJp6n2w=\n")
@ -457,10 +462,12 @@ func TestRTSPAuthFail(t *testing.T) {
}, },
} { } {
t.Run(ca.name, func(t *testing.T) { t.Run(ca.name, func(t *testing.T) {
p, ok := testProgram("paths:\n" + p, ok := testProgram(
" all:\n" + "rtmpDisable: yes\n" +
" publishUser: testuser\n" + "paths:\n" +
" publishPass: testpass\n") " all:\n" +
" publishUser: testuser\n" +
" publishPass: testpass\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -513,10 +520,12 @@ func TestRTSPAuthFail(t *testing.T) {
}, },
} { } {
t.Run(ca.name, func(t *testing.T) { t.Run(ca.name, func(t *testing.T) {
p, ok := testProgram("paths:\n" + p, ok := testProgram(
" all:\n" + "rtmpDisable: yes\n" +
" readUser: testuser\n" + "paths:\n" +
" readPass: testpass\n") " all:\n" +
" readUser: testuser\n" +
" readPass: testpass\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -549,7 +558,8 @@ func TestRTSPAuthFail(t *testing.T) {
} }
func TestRTSPAuthIpFail(t *testing.T) { func TestRTSPAuthIpFail(t *testing.T) {
p, ok := testProgram("paths:\n" + p, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" all:\n" + " all:\n" +
" publishIps: [127.0.0.1/32]\n") " publishIps: [127.0.0.1/32]\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
@ -574,7 +584,8 @@ func TestRTSPAutomaticProtocol(t *testing.T) {
"ffmpeg", "ffmpeg",
} { } {
t.Run(source, func(t *testing.T) { t.Run(source, func(t *testing.T) {
p, ok := testProgram("protocols: [tcp]\n") p, ok := testProgram("rtmpDisable: yes\n" +
"protocols: [tcp]\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -606,7 +617,7 @@ func TestRTSPAutomaticProtocol(t *testing.T) {
} }
func TestRTSPPublisherOverride(t *testing.T) { func TestRTSPPublisherOverride(t *testing.T) {
p, ok := testProgram("") p, ok := testProgram("rtmpDisable: yes\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -662,7 +673,7 @@ func TestRTSPPath(t *testing.T) {
}, },
} { } {
t.Run(ca.name, func(t *testing.T) { t.Run(ca.name, func(t *testing.T) {
p, ok := testProgram("") p, ok := testProgram("rtmpDisable: yes\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -694,7 +705,8 @@ func TestRTSPPath(t *testing.T) {
func TestRTSPNonCompliantFrameSize(t *testing.T) { func TestRTSPNonCompliantFrameSize(t *testing.T) {
t.Run("publish", func(t *testing.T) { t.Run("publish", func(t *testing.T) {
p, ok := testProgram("readBufferSize: 4500\n") p, ok := testProgram("rtmpDisable: yes\n" +
"readBufferSize: 4500\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -724,7 +736,8 @@ func TestRTSPNonCompliantFrameSize(t *testing.T) {
}) })
t.Run("proxy", func(t *testing.T) { t.Run("proxy", func(t *testing.T) {
p1, ok := testProgram("protocols: [tcp]\n" + p1, ok := testProgram("rtmpDisable: yes\n" +
"protocols: [tcp]\n" +
"readBufferSize: 4500\n") "readBufferSize: 4500\n")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p1.close() defer p1.close()
@ -745,7 +758,8 @@ func TestRTSPNonCompliantFrameSize(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer source.Close() defer source.Close()
p2, ok := testProgram("protocols: [tcp]\n" + p2, ok := testProgram("rtmpDisable: yes\n" +
"protocols: [tcp]\n" +
"readBufferSize: 4500\n" + "readBufferSize: 4500\n" +
"rtspPort: 8555\n" + "rtspPort: 8555\n" +
"paths:\n" + "paths:\n" +
@ -780,7 +794,8 @@ func TestRTSPNonCompliantFrameSize(t *testing.T) {
} }
func TestRTSPRedirect(t *testing.T) { func TestRTSPRedirect(t *testing.T) {
p1, ok := testProgram("paths:\n" + p1, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" path1:\n" + " path1:\n" +
" source: redirect\n" + " source: redirect\n" +
" sourceRedirect: rtsp://" + ownDockerIP + ":8554/path2\n" + " sourceRedirect: rtsp://" + ownDockerIP + ":8554/path2\n" +
@ -827,7 +842,8 @@ func TestRTSPFallback(t *testing.T) {
return "/path2" return "/path2"
}() }()
p1, ok := testProgram("paths:\n" + p1, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" path1:\n" + " path1:\n" +
" fallback: " + val + "\n" + " fallback: " + val + "\n" +
" path2:\n") " path2:\n")
@ -878,7 +894,8 @@ wait
t.Run("describe", func(t *testing.T) { t.Run("describe", func(t *testing.T) {
defer os.Remove(doneFile) defer os.Remove(doneFile)
p1, ok := testProgram(fmt.Sprintf("paths:\n"+ p1, ok := testProgram(fmt.Sprintf("rtmpDisable: yes\n"+
"paths:\n"+
" all:\n"+ " all:\n"+
" runOnDemand: %s\n"+ " runOnDemand: %s\n"+
" runOnDemandCloseAfter: 2s\n", onDemandFile)) " runOnDemandCloseAfter: 2s\n", onDemandFile))
@ -918,7 +935,8 @@ wait
t.Run("describe and setup", func(t *testing.T) { t.Run("describe and setup", func(t *testing.T) {
defer os.Remove(doneFile) defer os.Remove(doneFile)
p1, ok := testProgram(fmt.Sprintf("paths:\n"+ p1, ok := testProgram(fmt.Sprintf("rtmpDisable: yes\n"+
"paths:\n"+
" all:\n"+ " all:\n"+
" runOnDemand: %s\n"+ " runOnDemand: %s\n"+
" runOnDemandCloseAfter: 2s\n", onDemandFile)) " runOnDemandCloseAfter: 2s\n", onDemandFile))
@ -983,7 +1001,8 @@ wait
t.Run("setup", func(t *testing.T) { t.Run("setup", func(t *testing.T) {
defer os.Remove(doneFile) defer os.Remove(doneFile)
p1, ok := testProgram(fmt.Sprintf("paths:\n"+ p1, ok := testProgram(fmt.Sprintf("rtmpDisable: yes\n"+
"paths:\n"+
" all:\n"+ " all:\n"+
" runOnDemand: %s\n"+ " runOnDemand: %s\n"+
" runOnDemandCloseAfter: 2s\n", onDemandFile)) " runOnDemandCloseAfter: 2s\n", onDemandFile))
@ -1034,7 +1053,7 @@ wait
} }
func TestRTMPPublish(t *testing.T) { func TestRTMPPublish(t *testing.T) {
p, ok := testProgram("rtmpEnable: yes\n") p, ok := testProgram("")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -1064,7 +1083,7 @@ func TestRTMPPublish(t *testing.T) {
} }
func TestRTMPRead(t *testing.T) { func TestRTMPRead(t *testing.T) {
p, ok := testProgram("rtmpEnable: yes\n") p, ok := testProgram("")
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
@ -1094,7 +1113,7 @@ func TestRTMPRead(t *testing.T) {
func TestRTMPAuth(t *testing.T) { func TestRTMPAuth(t *testing.T) {
t.Run("publish", func(t *testing.T) { t.Run("publish", func(t *testing.T) {
p, ok := testProgram("rtmpEnable: yes\n" + p, ok := testProgram("rtspDisable: yes\n" +
"paths:\n" + "paths:\n" +
" all:\n" + " all:\n" +
" publishUser: testuser\n" + " publishUser: testuser\n" +
@ -1127,7 +1146,7 @@ func TestRTMPAuth(t *testing.T) {
}) })
t.Run("read", func(t *testing.T) { t.Run("read", func(t *testing.T) {
p, ok := testProgram("rtmpEnable: yes\n" + p, ok := testProgram("rtspDisable: yes\n" +
"paths:\n" + "paths:\n" +
" all:\n" + " all:\n" +
" readUser: testuser\n" + " readUser: testuser\n" +
@ -1162,7 +1181,7 @@ func TestRTMPAuth(t *testing.T) {
func TestRTMPAuthFail(t *testing.T) { func TestRTMPAuthFail(t *testing.T) {
t.Run("publish", func(t *testing.T) { t.Run("publish", func(t *testing.T) {
p, ok := testProgram("rtmpEnable: yes\n" + p, ok := testProgram("rtspDisable: yes\n" +
"paths:\n" + "paths:\n" +
" all:\n" + " all:\n" +
" publishUser: testuser2\n" + " publishUser: testuser2\n" +
@ -1195,7 +1214,7 @@ func TestRTMPAuthFail(t *testing.T) {
}) })
t.Run("read", func(t *testing.T) { t.Run("read", func(t *testing.T) {
p, ok := testProgram("rtmpEnable: yes\n" + p, ok := testProgram("rtspDisable: yes\n" +
"paths:\n" + "paths:\n" +
" all:\n" + " all:\n" +
" readUser: testuser2\n" + " readUser: testuser2\n" +
@ -1239,7 +1258,8 @@ func TestSource(t *testing.T) {
t.Run(source, func(t *testing.T) { t.Run(source, func(t *testing.T) {
switch source { switch source {
case "rtsp_udp", "rtsp_tcp": case "rtsp_udp", "rtsp_tcp":
p1, ok := testProgram("rtspPort: 8555\n" + p1, ok := testProgram("rtmpDisable: yes\n" +
"rtspPort: 8555\n" +
"rtpPort: 8100\n" + "rtpPort: 8100\n" +
"rtcpPort: 8101\n" + "rtcpPort: 8101\n" +
"paths:\n" + "paths:\n" +
@ -1261,7 +1281,8 @@ func TestSource(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer cnt1.close() defer cnt1.close()
p2, ok := testProgram("paths:\n" + p2, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" proxied:\n" + " proxied:\n" +
" source: rtsp://testuser:testpass@localhost:8555/teststream\n" + " source: rtsp://testuser:testpass@localhost:8555/teststream\n" +
" sourceProtocol: " + source[len("rtsp_"):] + "\n" + " sourceProtocol: " + source[len("rtsp_"):] + "\n" +
@ -1278,7 +1299,8 @@ func TestSource(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer os.Remove(serverKeyFpath) defer os.Remove(serverKeyFpath)
p, ok := testProgram("rtspPort: 8555\n" + p, ok := testProgram("rtmpDisable: yes\n" +
"rtspPort: 8555\n" +
"rtpPort: 8100\n" + "rtpPort: 8100\n" +
"rtcpPort: 8101\n" + "rtcpPort: 8101\n" +
"readTimeout: 20s\n" + "readTimeout: 20s\n" +
@ -1306,7 +1328,8 @@ func TestSource(t *testing.T) {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
p2, ok := testProgram("paths:\n" + p2, ok := testProgram("rtmpDisable: yes\n" +
"paths:\n" +
" proxied:\n" + " proxied:\n" +
" source: rtsps://testuser:testpass@localhost:8555/teststream\n" + " source: rtsps://testuser:testpass@localhost:8555/teststream\n" +
" sourceOnDemand: yes\n") " sourceOnDemand: yes\n")

View File

@ -35,6 +35,8 @@ runOnConnectRestart: no
############################################### ###############################################
# RTSP options # RTSP options
# disable support for the RTSP protocol.
rtspDisable: no
# supported RTSP stream protocols. # supported RTSP stream protocols.
# UDP is the most performant, but can cause problems if there's a NAT between # UDP is the most performant, but can cause problems if there's a NAT between
# server and clients, and doesn't support encryption. # server and clients, and doesn't support encryption.
@ -66,8 +68,8 @@ readBufferSize: 2048
############################################### ###############################################
# RTMP options # RTMP options
# enable a RTMP listener that allows to receive streams with RTMP. # disable support for the RTMP protocol.
rtmpEnable: no rtmpDisable: no
# port of the RTMP listener. # port of the RTMP listener.
rtmpPort: 1935 rtmpPort: 1935