Browse Source

support automatic protocol selection when proxying rtsp

pull/169/head
aler9 5 years ago
parent
commit
a9dee11496
  1. 2
      go.mod
  2. 4
      go.sum
  3. 8
      internal/client/client.go
  4. 64
      internal/conf/pathconf.go
  5. 8
      internal/path/path.go
  6. 4
      internal/sourcertsp/source.go
  7. 13
      main_test.go
  8. 4
      rtsp-simple-server.yml

2
go.mod

@ -5,7 +5,7 @@ go 1.15
require ( require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/aler9/gortsplib v0.0.0-20201120083135-e66459731e97 github.com/aler9/gortsplib v0.0.0-20201121121323-a6d0fc140b6e
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 github.com/fsnotify/fsnotify v1.4.9
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51

4
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/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 h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aler9/gortsplib v0.0.0-20201120083135-e66459731e97 h1:sefesnUXzUHF4fhS+rnpON5MpMOjka5YFka9P5qiS5s= github.com/aler9/gortsplib v0.0.0-20201121121323-a6d0fc140b6e h1:4BltbY0GVgVQntou5KQGpE0fL33tRq5o1zPY5pbyrlU=
github.com/aler9/gortsplib v0.0.0-20201120083135-e66459731e97/go.mod h1:6yKsTNIrCapRz90WHQtyFV/rKK0TT+QapxUXNqSJi9M= github.com/aler9/gortsplib v0.0.0-20201121121323-a6d0fc140b6e/go.mod h1:6yKsTNIrCapRz90WHQtyFV/rKK0TT+QapxUXNqSJi9M=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=

8
internal/client/client.go

@ -205,12 +205,12 @@ func (c *Client) run() {
defer c.wg.Done() defer c.wg.Done()
defer c.log("disconnected") defer c.log("disconnected")
var onConnectCmd *externalcmd.ExternalCmd
if c.runOnConnect != "" { if c.runOnConnect != "" {
onConnectCmd = externalcmd.New(c.runOnConnect, c.runOnConnectRestart, externalcmd.Environment{ onConnectCmd := externalcmd.New(c.runOnConnect, c.runOnConnectRestart, externalcmd.Environment{
Path: "", Path: "",
Port: strconv.FormatInt(int64(c.rtspPort), 10), Port: strconv.FormatInt(int64(c.rtspPort), 10),
}) })
defer onConnectCmd.Close()
} }
for { for {
@ -223,10 +223,6 @@ func (c *Client) run() {
c.path.OnClientRemove(c) c.path.OnClientRemove(c)
c.path = nil c.path = nil
} }
if onConnectCmd != nil {
onConnectCmd.Close()
}
} }
type errAuthNotCritical struct { type errAuthNotCritical struct {

64
internal/conf/pathconf.go

@ -18,33 +18,33 @@ const userPassSupportedChars = "A-Z,0-9,!,$,(,),*,+,.,;,<,=,>,[,],^,_,-,{,}"
// PathConf is a path configuration. // PathConf is a path configuration.
type PathConf struct { type PathConf struct {
Regexp *regexp.Regexp `yaml:"-" json:"-"` Regexp *regexp.Regexp `yaml:"-" json:"-"`
Source string `yaml:"source"` Source string `yaml:"source"`
SourceProtocol string `yaml:"sourceProtocol"` SourceProtocol string `yaml:"sourceProtocol"`
SourceProtocolParsed gortsplib.StreamProtocol `yaml:"-" json:"-"` SourceProtocolParsed *gortsplib.StreamProtocol `yaml:"-" json:"-"`
SourceOnDemand bool `yaml:"sourceOnDemand"` SourceOnDemand bool `yaml:"sourceOnDemand"`
SourceOnDemandStartTimeout time.Duration `yaml:"sourceOnDemandStartTimeout"` SourceOnDemandStartTimeout time.Duration `yaml:"sourceOnDemandStartTimeout"`
SourceOnDemandCloseAfter time.Duration `yaml:"sourceOnDemandCloseAfter"` SourceOnDemandCloseAfter time.Duration `yaml:"sourceOnDemandCloseAfter"`
SourceRedirect string `yaml:"sourceRedirect"` SourceRedirect string `yaml:"sourceRedirect"`
Fallback string `yaml:"fallback"` Fallback string `yaml:"fallback"`
RunOnInit string `yaml:"runOnInit"` RunOnInit string `yaml:"runOnInit"`
RunOnInitRestart bool `yaml:"runOnInitRestart"` RunOnInitRestart bool `yaml:"runOnInitRestart"`
RunOnDemand string `yaml:"runOnDemand"` RunOnDemand string `yaml:"runOnDemand"`
RunOnDemandRestart bool `yaml:"runOnDemandRestart"` RunOnDemandRestart bool `yaml:"runOnDemandRestart"`
RunOnDemandStartTimeout time.Duration `yaml:"runOnDemandStartTimeout"` RunOnDemandStartTimeout time.Duration `yaml:"runOnDemandStartTimeout"`
RunOnDemandCloseAfter time.Duration `yaml:"runOnDemandCloseAfter"` RunOnDemandCloseAfter time.Duration `yaml:"runOnDemandCloseAfter"`
RunOnPublish string `yaml:"runOnPublish"` RunOnPublish string `yaml:"runOnPublish"`
RunOnPublishRestart bool `yaml:"runOnPublishRestart"` RunOnPublishRestart bool `yaml:"runOnPublishRestart"`
RunOnRead string `yaml:"runOnRead"` RunOnRead string `yaml:"runOnRead"`
RunOnReadRestart bool `yaml:"runOnReadRestart"` RunOnReadRestart bool `yaml:"runOnReadRestart"`
PublishUser string `yaml:"publishUser"` PublishUser string `yaml:"publishUser"`
PublishPass string `yaml:"publishPass"` PublishPass string `yaml:"publishPass"`
PublishIps []string `yaml:"publishIps"` PublishIps []string `yaml:"publishIps"`
PublishIpsParsed []interface{} `yaml:"-" json:"-"` PublishIpsParsed []interface{} `yaml:"-" json:"-"`
ReadUser string `yaml:"readUser"` ReadUser string `yaml:"readUser"`
ReadPass string `yaml:"readPass"` ReadPass string `yaml:"readPass"`
ReadIps []string `yaml:"readIps"` ReadIps []string `yaml:"readIps"`
ReadIpsParsed []interface{} `yaml:"-" json:"-"` ReadIpsParsed []interface{} `yaml:"-" json:"-"`
} }
func (pconf *PathConf) fillAndCheck(name string) error { func (pconf *PathConf) fillAndCheck(name string) error {
@ -94,15 +94,19 @@ func (pconf *PathConf) fillAndCheck(name string) error {
} }
if pconf.SourceProtocol == "" { if pconf.SourceProtocol == "" {
pconf.SourceProtocol = "udp" pconf.SourceProtocol = "automatic"
} }
switch pconf.SourceProtocol { switch pconf.SourceProtocol {
case "udp": case "udp":
pconf.SourceProtocolParsed = gortsplib.StreamProtocolUDP v := gortsplib.StreamProtocolUDP
pconf.SourceProtocolParsed = &v
case "tcp": case "tcp":
pconf.SourceProtocolParsed = gortsplib.StreamProtocolTCP v := gortsplib.StreamProtocolTCP
pconf.SourceProtocolParsed = &v
case "automatic":
default: default:
return fmt.Errorf("unsupported protocol '%s'", pconf.SourceProtocol) return fmt.Errorf("unsupported protocol '%s'", pconf.SourceProtocol)

8
internal/path/path.go

@ -155,7 +155,6 @@ type Path struct {
sourceTrackCount int sourceTrackCount int
sourceSdp []byte sourceSdp []byte
readers *readersMap readers *readersMap
onInitCmd *externalcmd.ExternalCmd
onDemandCmd *externalcmd.ExternalCmd onDemandCmd *externalcmd.ExternalCmd
describeTimer *time.Timer describeTimer *time.Timer
sourceCloseTimer *time.Timer sourceCloseTimer *time.Timer
@ -245,9 +244,10 @@ func (pa *Path) run() {
pa.startExternalSource() pa.startExternalSource()
} }
var onInitCmd *externalcmd.ExternalCmd
if pa.conf.RunOnInit != "" { if pa.conf.RunOnInit != "" {
pa.Log("on init command started") pa.Log("on init command started")
pa.onInitCmd = externalcmd.New(pa.conf.RunOnInit, pa.conf.RunOnInitRestart, externalcmd.Environment{ onInitCmd = externalcmd.New(pa.conf.RunOnInit, pa.conf.RunOnInitRestart, externalcmd.Environment{
Path: pa.name, Path: pa.name,
Port: strconv.FormatInt(int64(pa.rtspPort), 10), Port: strconv.FormatInt(int64(pa.rtspPort), 10),
}) })
@ -363,9 +363,9 @@ outer:
pa.runOnDemandCloseTimer.Stop() pa.runOnDemandCloseTimer.Stop()
pa.closeTimer.Stop() pa.closeTimer.Stop()
if pa.onInitCmd != nil { if onInitCmd != nil {
pa.Log("on init command stopped") pa.Log("on init command stopped")
pa.onInitCmd.Close() onInitCmd.Close()
} }
if source, ok := pa.source.(sourceExternal); ok { if source, ok := pa.source.(sourceExternal); ok {

4
internal/sourcertsp/source.go

@ -25,7 +25,7 @@ type Parent interface {
// Source is a RTSP source. // Source is a RTSP source.
type Source struct { type Source struct {
ur string ur string
proto gortsplib.StreamProtocol proto *gortsplib.StreamProtocol
readTimeout time.Duration readTimeout time.Duration
writeTimeout time.Duration writeTimeout time.Duration
wg *sync.WaitGroup wg *sync.WaitGroup
@ -41,7 +41,7 @@ type Source struct {
// New allocates a Source. // New allocates a Source.
func New(ur string, func New(ur string,
proto gortsplib.StreamProtocol, proto *gortsplib.StreamProtocol,
readTimeout time.Duration, readTimeout time.Duration,
writeTimeout time.Duration, writeTimeout time.Duration,
wg *sync.WaitGroup, wg *sync.WaitGroup,

13
main_test.go

@ -187,7 +187,7 @@ func TestEnvironment(t *testing.T) {
require.Equal(t, &conf.PathConf{ require.Equal(t, &conf.PathConf{
Regexp: regexp.MustCompile("^.*$"), Regexp: regexp.MustCompile("^.*$"),
Source: "record", Source: "record",
SourceProtocol: "udp", SourceProtocol: "automatic",
SourceOnDemandStartTimeout: 10 * time.Second, SourceOnDemandStartTimeout: 10 * time.Second,
SourceOnDemandCloseAfter: 10 * time.Second, SourceOnDemandCloseAfter: 10 * time.Second,
ReadUser: "testuser", ReadUser: "testuser",
@ -199,9 +199,12 @@ func TestEnvironment(t *testing.T) {
pa, ok = p.conf.Paths["cam1"] pa, ok = p.conf.Paths["cam1"]
require.Equal(t, true, ok) require.Equal(t, true, ok)
require.Equal(t, &conf.PathConf{ require.Equal(t, &conf.PathConf{
Source: "rtsp://testing", Source: "rtsp://testing",
SourceProtocol: "tcp", SourceProtocol: "tcp",
SourceProtocolParsed: gortsplib.StreamProtocolTCP, SourceProtocolParsed: func() *gortsplib.StreamProtocol {
v := gortsplib.StreamProtocolTCP
return &v
}(),
SourceOnDemand: true, SourceOnDemand: true,
SourceOnDemandStartTimeout: 10 * time.Second, SourceOnDemandStartTimeout: 10 * time.Second,
SourceOnDemandCloseAfter: 10 * time.Second, SourceOnDemandCloseAfter: 10 * time.Second,
@ -222,7 +225,7 @@ func TestEnvironmentNoFile(t *testing.T) {
require.Equal(t, true, ok) require.Equal(t, true, ok)
require.Equal(t, &conf.PathConf{ require.Equal(t, &conf.PathConf{
Source: "rtsp://testing", Source: "rtsp://testing",
SourceProtocol: "udp", SourceProtocol: "automatic",
SourceOnDemandStartTimeout: 10 * time.Second, SourceOnDemandStartTimeout: 10 * time.Second,
SourceOnDemandCloseAfter: 10 * time.Second, SourceOnDemandCloseAfter: 10 * time.Second,
RunOnDemandStartTimeout: 10 * time.Second, RunOnDemandStartTimeout: 10 * time.Second,

4
rtsp-simple-server.yml

@ -48,8 +48,8 @@ paths:
source: record 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. # pull the stream. available options are "automatic", "udp", "tcp".
sourceProtocol: udp 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. # one reader is connected, saving bandwidth.
sourceOnDemand: no sourceOnDemand: no

Loading…
Cancel
Save