diff --git a/README.md b/README.md index 31c0bc66..1e95c9ff 100644 --- a/README.md +++ b/README.md @@ -506,7 +506,7 @@ In some scenarios, the server can send incomplete or corrupted frames. This can readBufferCount: 1024 ``` -* The stream throughput is too big and the stream can't be sent correctly with the UDP stream protocol. UDP is more performant, faster and more efficient than TCP, but doesn't have a retransmission mechanism, that is needed in case of streams that need a large bandwidth. A solution consists in switching to TCP: +* The stream throughput is too big and the stream can't be sent correctly with the UDP transport. UDP is more performant, faster and more efficient than TCP, but doesn't have a retransmission mechanism, that is needed in case of streams that need a large bandwidth. A solution consists in switching to TCP: ```yml protocols: [tcp] diff --git a/go.mod b/go.mod index 6e1725d4..40c3def5 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect - github.com/aler9/gortsplib v0.0.0-20211001120239-c084f1b0f3b7 + github.com/aler9/gortsplib v0.0.0-20211022160112-22501a39ddf6 github.com/asticode/go-astits v1.10.0 github.com/fsnotify/fsnotify v1.4.9 github.com/gin-gonic/gin v1.7.2 diff --git a/go.sum b/go.sum index 2119cff0..73248fed 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aler9/gortsplib v0.0.0-20211001120239-c084f1b0f3b7 h1:MV3JKPe6Tqf1ZwtJRSopzzugatjVRzLsHXI9BgTq4qM= -github.com/aler9/gortsplib v0.0.0-20211001120239-c084f1b0f3b7/go.mod h1:fyQrQyHo8QvdR/h357tkv1g36VesZlzEPsdAu2VrHHc= +github.com/aler9/gortsplib v0.0.0-20211022160112-22501a39ddf6 h1:dccH0/W0hfxXt054maCTjf96V4e5O9KJCH8cuNlYFck= +github.com/aler9/gortsplib v0.0.0-20211022160112-22501a39ddf6/go.mod h1:fyQrQyHo8QvdR/h357tkv1g36VesZlzEPsdAu2VrHHc= github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927 h1:95mXJ5fUCYpBRdSOnLAQAdJHHKxxxJrVCiaqDi965YQ= github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927/go.mod h1:vzuE21rowz+lT1NGsWbreIvYulgBpCGnQyeTyFblUHc= github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8= diff --git a/internal/conf/conf.go b/internal/conf/conf.go index 17bcb547..e09365ce 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -9,6 +9,7 @@ import ( "reflect" "time" + "github.com/aler9/gortsplib" "github.com/aler9/gortsplib/pkg/headers" "golang.org/x/crypto/nacl/secretbox" "gopkg.in/yaml.v2" @@ -261,15 +262,15 @@ func (conf *Conf) CheckAndFillMissing() error { if len(conf.Protocols) == 0 { conf.Protocols = Protocols{ - ProtocolUDP: {}, - ProtocolMulticast: {}, - ProtocolTCP: {}, + Protocol(gortsplib.TransportUDP): {}, + Protocol(gortsplib.TransportUDPMulticast): {}, + Protocol(gortsplib.TransportTCP): {}, } } if conf.Encryption == EncryptionStrict { - if _, ok := conf.Protocols[ProtocolUDP]; ok { - return fmt.Errorf("strict encryption can't be used with the UDP stream protocol") + if _, ok := conf.Protocols[Protocol(gortsplib.TransportUDP)]; ok { + return fmt.Errorf("strict encryption can't be used with the UDP transport") } } diff --git a/internal/conf/conf_test.go b/internal/conf/conf_test.go index 9eb7a545..ef108f3c 100644 --- a/internal/conf/conf_test.go +++ b/internal/conf/conf_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/aler9/gortsplib" "github.com/stretchr/testify/require" "golang.org/x/crypto/nacl/secretbox" @@ -101,7 +102,7 @@ func TestConfFromFileAndEnv(t *testing.T) { require.NoError(t, err) require.Equal(t, true, hasFile) - require.Equal(t, Protocols{ProtocolTCP: {}}, conf.Protocols) + require.Equal(t, Protocols{Protocol(gortsplib.TransportTCP): {}}, conf.Protocols) pa, ok := conf.Paths["cam1"] require.Equal(t, true, ok) diff --git a/internal/conf/protocol.go b/internal/conf/protocol.go index 0843b011..69e3fbe0 100644 --- a/internal/conf/protocol.go +++ b/internal/conf/protocol.go @@ -5,17 +5,12 @@ import ( "fmt" "sort" "strings" + + "github.com/aler9/gortsplib" ) -// Protocol is a RTSP stream protocol. -type Protocol int - -// supported RTSP protocols. -const ( - ProtocolUDP Protocol = iota - ProtocolMulticast - ProtocolTCP -) +// Protocol is a RTSP transport. +type Protocol gortsplib.Transport // Protocols is the protocols parameter. type Protocols map[Protocol]struct{} @@ -29,10 +24,10 @@ func (d Protocols) MarshalJSON() ([]byte, error) { var v string switch p { - case ProtocolUDP: + case Protocol(gortsplib.TransportUDP): v = "udp" - case ProtocolMulticast: + case Protocol(gortsplib.TransportUDPMulticast): v = "multicast" default: @@ -60,13 +55,13 @@ func (d *Protocols) UnmarshalJSON(b []byte) error { for _, proto := range in { switch proto { case "udp": - (*d)[ProtocolUDP] = struct{}{} + (*d)[Protocol(gortsplib.TransportUDP)] = struct{}{} case "multicast": - (*d)[ProtocolMulticast] = struct{}{} + (*d)[Protocol(gortsplib.TransportUDPMulticast)] = struct{}{} case "tcp": - (*d)[ProtocolTCP] = struct{}{} + (*d)[Protocol(gortsplib.TransportTCP)] = struct{}{} default: return fmt.Errorf("invalid protocol: %s", proto) diff --git a/internal/conf/sourceprotocol.go b/internal/conf/sourceprotocol.go index 3d95d6c4..6cf65692 100644 --- a/internal/conf/sourceprotocol.go +++ b/internal/conf/sourceprotocol.go @@ -9,21 +9,21 @@ import ( // SourceProtocol is the sourceProtocol parameter. type SourceProtocol struct { - *gortsplib.ClientProtocol + *gortsplib.Transport } // MarshalJSON marshals a SourceProtocol into JSON. func (d SourceProtocol) MarshalJSON() ([]byte, error) { var out string - if d.ClientProtocol == nil { + if d.Transport == nil { out = "automatic" } else { - switch *d.ClientProtocol { - case gortsplib.ClientProtocolUDP: + switch *d.Transport { + case gortsplib.TransportUDP: out = "udp" - case gortsplib.ClientProtocolMulticast: + case gortsplib.TransportUDPMulticast: out = "multicast" default: @@ -43,16 +43,16 @@ func (d *SourceProtocol) UnmarshalJSON(b []byte) error { switch in { case "udp": - v := gortsplib.ClientProtocolUDP - d.ClientProtocol = &v + v := gortsplib.TransportUDP + d.Transport = &v case "multicast": - v := gortsplib.ClientProtocolMulticast - d.ClientProtocol = &v + v := gortsplib.TransportUDPMulticast + d.Transport = &v case "tcp": - v := gortsplib.ClientProtocolTCP - d.ClientProtocol = &v + v := gortsplib.TransportTCP + d.Transport = &v case "automatic": diff --git a/internal/core/core.go b/internal/core/core.go index 7ae9acff..3021a85e 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -7,6 +7,7 @@ import ( "reflect" "sync/atomic" + "github.com/aler9/gortsplib" "github.com/gin-gonic/gin" "gopkg.in/alecthomas/kingpin.v2" @@ -240,8 +241,8 @@ func (p *Core) createResources(initial bool) error { (p.conf.Encryption == conf.EncryptionNo || p.conf.Encryption == conf.EncryptionOptional) { if p.rtspServer == nil { - _, useUDP := p.conf.Protocols[conf.ProtocolUDP] - _, useMulticast := p.conf.Protocols[conf.ProtocolMulticast] + _, useUDP := p.conf.Protocols[conf.Protocol(gortsplib.TransportUDP)] + _, useMulticast := p.conf.Protocols[conf.Protocol(gortsplib.TransportUDPMulticast)] p.rtspServer, err = newRTSPServer( p.ctx, p.conf.RTSPAddress, diff --git a/internal/core/rtsp_server_test.go b/internal/core/rtsp_server_test.go index 9998e7c4..5040041c 100644 --- a/internal/core/rtsp_server_test.go +++ b/internal/core/rtsp_server_test.go @@ -175,8 +175,9 @@ func TestRTSPServerPublishRead(t *testing.T) { }() cnt2, err := newContainer("gstreamer", "read", []string{ - "rtspsrc location=" + proto + "://127.0.0.1:" + port + "/teststream protocols=" + ps + - " tls-validation-flags=0 latency=0 " + + "rtspsrc location=" + proto + "://127.0.0.1:" + port + "/teststream " + + "protocols=" + ps + " " + + "tls-validation-flags=0 latency=0 " + "! application/x-rtp,media=video ! decodebin ! exitafterframe ! fakesink", }) require.NoError(t, err) @@ -525,8 +526,8 @@ func TestRTSPServerNonCompliantFrameSize(t *testing.T) { require.NoError(t, err) client := &gortsplib.Client{ - Protocol: func() *gortsplib.ClientProtocol { - v := gortsplib.ClientProtocolTCP + Transport: func() *gortsplib.Transport { + v := gortsplib.TransportTCP return &v }(), ReadBufferSize: 4500, @@ -576,8 +577,8 @@ func TestRTSPServerNonCompliantFrameSize(t *testing.T) { require.NoError(t, err) client := &gortsplib.Client{ - Protocol: func() *gortsplib.ClientProtocol { - v := gortsplib.ClientProtocolTCP + Transport: func() *gortsplib.Transport { + v := gortsplib.TransportTCP return &v }(), ReadBufferSize: 4500, @@ -810,9 +811,9 @@ wait Header: base.Header{ "CSeq": base.HeaderValue{"2"}, "Transport": headers.Transport{ - Protocol: base.StreamProtocolTCP, - Delivery: func() *base.StreamDelivery { - v := base.StreamDeliveryUnicast + Protocol: headers.TransportProtocolTCP, + Delivery: func() *headers.TransportDelivery { + v := headers.TransportDeliveryUnicast return &v }(), Mode: func() *headers.TransportMode { @@ -863,9 +864,9 @@ wait Header: base.Header{ "CSeq": base.HeaderValue{"1"}, "Transport": headers.Transport{ - Protocol: base.StreamProtocolTCP, - Delivery: func() *base.StreamDelivery { - v := base.StreamDeliveryUnicast + Protocol: headers.TransportProtocolTCP, + Delivery: func() *headers.TransportDelivery { + v := headers.TransportDeliveryUnicast return &v }(), Mode: func() *headers.TransportMode { diff --git a/internal/core/rtsp_session.go b/internal/core/rtsp_session.go index a76cf3e9..ccb0accd 100644 --- a/internal/core/rtsp_session.go +++ b/internal/core/rtsp_session.go @@ -96,13 +96,6 @@ func (s *rtspSession) RemoteAddr() net.Addr { return s.author.NetConn().RemoteAddr() } -func (s *rtspSession) displayedProtocol() string { - if *s.ss.SetuppedDelivery() == base.StreamDeliveryMulticast { - return "UDP-multicast" - } - return s.ss.SetuppedProtocol().String() -} - func (s *rtspSession) log(level logger.Level, format string, args ...interface{}) { s.parent.Log(level, "[session %s] "+format, append([]interface{}{s.id}, args...)...) } @@ -174,24 +167,27 @@ func (s *rtspSession) OnAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnno // OnSetup is called by rtspServer. func (s *rtspSession) OnSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCtx, ) (*base.Response, *gortsplib.ServerStream, error) { - if ctx.Transport.Protocol == base.StreamProtocolUDP { - if _, ok := s.protocols[conf.ProtocolUDP]; !ok { + switch ctx.Transport { + case gortsplib.TransportUDP: + if _, ok := s.protocols[conf.Protocol(gortsplib.TransportUDP)]; !ok { return &base.Response{ StatusCode: base.StatusUnsupportedTransport, }, nil, nil } - if ctx.Transport.Delivery != nil && *ctx.Transport.Delivery == base.StreamDeliveryMulticast { - if _, ok := s.protocols[conf.ProtocolMulticast]; !ok { - return &base.Response{ - StatusCode: base.StatusUnsupportedTransport, - }, nil, nil - } + case gortsplib.TransportUDPMulticast: + if _, ok := s.protocols[conf.Protocol(gortsplib.TransportUDPMulticast)]; !ok { + return &base.Response{ + StatusCode: base.StatusUnsupportedTransport, + }, nil, nil + } + + default: // TCP + if _, ok := s.protocols[conf.Protocol(gortsplib.TransportTCP)]; !ok { + return &base.Response{ + StatusCode: base.StatusUnsupportedTransport, + }, nil, nil } - } else if _, ok := s.protocols[conf.ProtocolTCP]; !ok { - return &base.Response{ - StatusCode: base.StatusUnsupportedTransport, - }, nil, nil } switch s.ss.State() { @@ -347,7 +343,7 @@ func (s *rtspSession) OnReaderAccepted() { } return "tracks" }(), - s.displayedProtocol()) + s.ss.SetuppedTransport()) } // OnReaderFrame implements reader. @@ -396,7 +392,7 @@ func (s *rtspSession) OnPublisherAccepted(tracksLen int) { } return "tracks" }(), - s.displayedProtocol()) + s.ss.SetuppedTransport()) } // OnFrame is called by rtspServer. diff --git a/internal/core/rtsp_source.go b/internal/core/rtsp_source.go index 86f7cc6d..3fbab4ae 100644 --- a/internal/core/rtsp_source.go +++ b/internal/core/rtsp_source.go @@ -118,7 +118,7 @@ func (s *rtspSource) runInner() bool { s.log(logger.Debug, "connecting") client := &gortsplib.Client{ - Protocol: s.proto.ClientProtocol, + Transport: s.proto.Transport, TLSConfig: &tls.Config{ InsecureSkipVerify: true, VerifyConnection: func(cs tls.ConnectionState) error { diff --git a/rtsp-simple-server.yml b/rtsp-simple-server.yml index 709137c2..4afe61a8 100644 --- a/rtsp-simple-server.yml +++ b/rtsp-simple-server.yml @@ -45,7 +45,7 @@ runOnConnectRestart: no # disable support for the RTSP protocol. rtspDisable: no -# supported RTSP stream protocols. +# supported RTSP transport protocols. # UDP is the most performant, but doesn't work when there's a NAT/firewall between # server and clients, and doesn't support encryption. # UDP-multicast allows to save bandwidth when clients are all in the same LAN.