diff --git a/README.md b/README.md index cb103fe3..78454618 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ WARNING: RTSP is a plain protocol, and the credentials can be intercepted and re #### Client count -The current number of clients, publishers and receivers is printed in each log line; for instance, the line: +The current number of clients, publishers and readers is printed in each log line; for instance, the line: ``` 2020/01/01 00:00:00 [2/1/1] [client 127.0.0.1:44428] OPTION ``` diff --git a/conf.go b/conf.go index 87073787..69487897 100644 --- a/conf.go +++ b/conf.go @@ -3,6 +3,7 @@ package main import ( "fmt" "io" + "net/url" "os" "regexp" "time" @@ -12,18 +13,20 @@ import ( ) type ConfPath struct { - Source string `yaml:"source"` - SourceProtocol string `yaml:"sourceProtocol"` - PublishUser string `yaml:"publishUser"` - PublishPass string `yaml:"publishPass"` - PublishIps []string `yaml:"publishIps"` - publishIpsParsed []interface{} - ReadUser string `yaml:"readUser"` - ReadPass string `yaml:"readPass"` - ReadIps []string `yaml:"readIps"` - readIpsParsed []interface{} - RunOnPublish string `yaml:"runOnPublish"` - RunOnRead string `yaml:"runOnRead"` + Source string `yaml:"source"` + sourceUrl *url.URL + SourceProtocol string `yaml:"sourceProtocol"` + sourceProtocolParsed gortsplib.StreamProtocol + PublishUser string `yaml:"publishUser"` + PublishPass string `yaml:"publishPass"` + PublishIps []string `yaml:"publishIps"` + publishIpsParsed []interface{} + ReadUser string `yaml:"readUser"` + ReadPass string `yaml:"readPass"` + ReadIps []string `yaml:"readIps"` + readIpsParsed []interface{} + RunOnPublish string `yaml:"runOnPublish"` + RunOnRead string `yaml:"runOnRead"` } type conf struct { @@ -198,6 +201,36 @@ func loadConf(fpath string, stdin io.Reader) (*conf, error) { if pconf.SourceProtocol == "" { pconf.SourceProtocol = "udp" } + + pconf.sourceUrl, err = url.Parse(pconf.Source) + if err != nil { + return nil, fmt.Errorf("'%s' is not a valid RTSP url", pconf.Source) + } + if pconf.sourceUrl.Scheme != "rtsp" { + return nil, fmt.Errorf("'%s' is not a valid RTSP url", pconf.Source) + } + if pconf.sourceUrl.Port() == "" { + pconf.sourceUrl.Host += ":554" + } + if pconf.sourceUrl.User != nil { + pass, _ := pconf.sourceUrl.User.Password() + user := pconf.sourceUrl.User.Username() + if user != "" && pass == "" || + user == "" && pass != "" { + fmt.Errorf("username and password must be both provided") + } + } + + switch pconf.SourceProtocol { + case "udp": + pconf.sourceProtocolParsed = gortsplib.StreamProtocolUdp + + case "tcp": + pconf.sourceProtocolParsed = gortsplib.StreamProtocolTcp + + default: + return nil, fmt.Errorf("unsupported protocol '%s'", pconf.SourceProtocol) + } } } diff --git a/go.mod b/go.mod index 8939e88d..cc36b0ac 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module rtsp-simple-server -go 1.13 +go 1.12 require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect diff --git a/main.go b/main.go index 0f833e02..7f7f87a2 100644 --- a/main.go +++ b/main.go @@ -162,20 +162,20 @@ type program struct { sources []*source publishers map[string]publisher publisherCount int - receiverCount int + readerCount int events chan programEvent done chan struct{} } -func newProgram(sargs []string, stdin io.Reader) (*program, error) { +func newProgram(args []string, stdin io.Reader) (*program, error) { k := kingpin.New("rtsp-simple-server", "rtsp-simple-server "+Version+"\n\nRTSP server.") argVersion := k.Flag("version", "print version").Bool() argConfPath := k.Arg("confpath", "path to a config file. The default is rtsp-simple-server.yml. Use 'stdin' to read config from stdin").Default("rtsp-simple-server.yml").String() - kingpin.MustParse(k.Parse(sargs)) + kingpin.MustParse(k.Parse(args)) if *argVersion == true { fmt.Println(Version) @@ -197,11 +197,7 @@ func newProgram(sargs []string, stdin io.Reader) (*program, error) { for path, pconf := range conf.Paths { if pconf.Source != "record" { - s, err := newSource(p, path, pconf.Source, pconf.SourceProtocol) - if err != nil { - return nil, err - } - + s := newSource(p, path, pconf.sourceUrl, pconf.sourceProtocolParsed) p.sources = append(p.sources, s) p.publishers[path] = s } @@ -249,7 +245,7 @@ func newProgram(sargs []string, stdin io.Reader) (*program, error) { func (p *program) log(format string, args ...interface{}) { log.Printf("[%d/%d/%d] "+format, append([]interface{}{len(p.clients), - p.publisherCount, p.receiverCount}, args...)...) + p.publisherCount, p.readerCount}, args...)...) } func (p *program) run() { @@ -349,12 +345,12 @@ outer: evt.res <- nil case programEventClientPlay2: - p.receiverCount += 1 + p.readerCount += 1 evt.client.state = clientStatePlay close(evt.done) case programEventClientPlayStop: - p.receiverCount -= 1 + p.readerCount -= 1 evt.client.state = clientStatePrePlay close(evt.done) diff --git a/source.go b/source.go index 93d0a4c4..110a0af6 100644 --- a/source.go +++ b/source.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "math/rand" "net" "net/url" @@ -33,40 +32,7 @@ type source struct { done chan struct{} } -func newSource(p *program, path string, sourceStr string, sourceProtocol string) (*source, error) { - u, err := url.Parse(sourceStr) - if err != nil { - return nil, fmt.Errorf("'%s' is not a valid RTSP url", sourceStr) - } - if u.Scheme != "rtsp" { - return nil, fmt.Errorf("'%s' is not a valid RTSP url", sourceStr) - } - if u.Port() == "" { - u.Host += ":554" - } - if u.User != nil { - pass, _ := u.User.Password() - user := u.User.Username() - if user != "" && pass == "" || - user == "" && pass != "" { - fmt.Errorf("username and password must be both provided") - } - } - - proto, err := func() (gortsplib.StreamProtocol, error) { - switch sourceProtocol { - case "udp": - return gortsplib.StreamProtocolUdp, nil - - case "tcp": - return gortsplib.StreamProtocolTcp, nil - } - return gortsplib.StreamProtocol(0), fmt.Errorf("unsupported protocol '%s'", sourceProtocol) - }() - if err != nil { - return nil, err - } - +func newSource(p *program, path string, u *url.URL, proto gortsplib.StreamProtocol) *source { s := &source{ p: p, path: path, @@ -76,7 +42,7 @@ func newSource(p *program, path string, sourceStr string, sourceProtocol string) done: make(chan struct{}), } - return s, nil + return s } func (s *source) log(format string, args ...interface{}) {