forked from External/mediamtx
add 'restart' option to all external commands
This commit is contained in:
parent
e511eb4ef1
commit
38b07ab68a
9 changed files with 191 additions and 115 deletions
|
|
@ -109,6 +109,7 @@ Edit `rtsp-simple-server.yml` and replace everything inside section `paths` with
|
||||||
paths:
|
paths:
|
||||||
cam:
|
cam:
|
||||||
runOnInit: ffmpeg -f v4l2 -i /dev/video0 -f rtsp rtsp://localhost:8554/$RTSP_SERVER_PATH
|
runOnInit: ffmpeg -f v4l2 -i /dev/video0 -f rtsp rtsp://localhost:8554/$RTSP_SERVER_PATH
|
||||||
|
runOnInitRestart: yes
|
||||||
```
|
```
|
||||||
|
|
||||||
After starting the server, the webcam is available on `rtsp://localhost:8554/cam`. The ffmpeg command works only on Linux; for Windows and Mac equivalents, read the [ffmpeg wiki](https://trac.ffmpeg.org/wiki/Capture/Webcam).
|
After starting the server, the webcam is available on `rtsp://localhost:8554/cam`. The ffmpeg command works only on Linux; for Windows and Mac equivalents, read the [ffmpeg wiki](https://trac.ffmpeg.org/wiki/Capture/Webcam).
|
||||||
|
|
@ -128,6 +129,7 @@ Then edit `rtsp-simple-server.yml` and replace everything inside section `paths`
|
||||||
paths:
|
paths:
|
||||||
cam:
|
cam:
|
||||||
runOnInit: gst-launch-1.0 rpicamsrc preview=false bitrate=2000000 keyframe-interval=50 ! video/x-h264,width=1920,height=1080,framerate=25/1 ! rtspclientsink location=rtsp://localhost:8554/$RTSP_SERVER_PATH
|
runOnInit: gst-launch-1.0 rpicamsrc preview=false bitrate=2000000 keyframe-interval=50 ! video/x-h264,width=1920,height=1080,framerate=25/1 ! rtspclientsink location=rtsp://localhost:8554/$RTSP_SERVER_PATH
|
||||||
|
runOnInitRestart: yes
|
||||||
```
|
```
|
||||||
|
|
||||||
After starting the server, the webcam is available on `rtsp://localhost:8554/cam`.
|
After starting the server, the webcam is available on `rtsp://localhost:8554/cam`.
|
||||||
|
|
@ -139,6 +141,7 @@ Edit `rtsp-simple-server.yml` and replace everything inside section `paths` with
|
||||||
paths:
|
paths:
|
||||||
ondemand:
|
ondemand:
|
||||||
runOnDemand: ffmpeg -re -stream_loop -1 -i file.ts -c copy -f rtsp rtsp://localhost:8554/$RTSP_SERVER_PATH
|
runOnDemand: ffmpeg -re -stream_loop -1 -i file.ts -c copy -f rtsp rtsp://localhost:8554/$RTSP_SERVER_PATH
|
||||||
|
runOnDemandRestart: yes
|
||||||
```
|
```
|
||||||
|
|
||||||
The command inserted into `runOnDemand` will start only when a client requests the path `ondemand`, therefore the file will start streaming only when requested.
|
The command inserted into `runOnDemand` will start only when a client requests the path `ondemand`, therefore the file will start streaming only when requested.
|
||||||
|
|
@ -151,6 +154,7 @@ paths:
|
||||||
all:
|
all:
|
||||||
original:
|
original:
|
||||||
runOnPublish: ffmpeg -i rtsp://localhost:8554/$RTSP_SERVER_PATH -b:a 64k -c:v libx264 -preset ultrafast -b:v 500k -max_muxing_queue_size 1024 -f rtsp rtsp://localhost:8554/compressed
|
runOnPublish: ffmpeg -i rtsp://localhost:8554/$RTSP_SERVER_PATH -b:a 64k -c:v libx264 -preset ultrafast -b:v 500k -max_muxing_queue_size 1024 -f rtsp rtsp://localhost:8554/compressed
|
||||||
|
runOnPublishRestart: yes
|
||||||
```
|
```
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
|
|
|
||||||
|
|
@ -97,15 +97,16 @@ type Parent interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
stats *stats.Stats
|
stats *stats.Stats
|
||||||
serverUdpRtp *serverudp.Server
|
serverUdpRtp *serverudp.Server
|
||||||
serverUdpRtcp *serverudp.Server
|
serverUdpRtcp *serverudp.Server
|
||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
runOnConnect string
|
runOnConnect string
|
||||||
protocols map[gortsplib.StreamProtocol]struct{}
|
runOnConnectRestart bool
|
||||||
conn *gortsplib.ConnServer
|
protocols map[gortsplib.StreamProtocol]struct{}
|
||||||
parent Parent
|
conn *gortsplib.ConnServer
|
||||||
|
parent Parent
|
||||||
|
|
||||||
state state
|
state state
|
||||||
path Path
|
path Path
|
||||||
|
|
@ -134,18 +135,20 @@ func New(
|
||||||
readTimeout time.Duration,
|
readTimeout time.Duration,
|
||||||
writeTimeout time.Duration,
|
writeTimeout time.Duration,
|
||||||
runOnConnect string,
|
runOnConnect string,
|
||||||
|
runOnConnectRestart bool,
|
||||||
protocols map[gortsplib.StreamProtocol]struct{},
|
protocols map[gortsplib.StreamProtocol]struct{},
|
||||||
nconn net.Conn,
|
nconn net.Conn,
|
||||||
parent Parent) *Client {
|
parent Parent) *Client {
|
||||||
|
|
||||||
c := &Client{
|
c := &Client{
|
||||||
wg: wg,
|
wg: wg,
|
||||||
stats: stats,
|
stats: stats,
|
||||||
serverUdpRtp: serverUdpRtp,
|
serverUdpRtp: serverUdpRtp,
|
||||||
serverUdpRtcp: serverUdpRtcp,
|
serverUdpRtcp: serverUdpRtcp,
|
||||||
readTimeout: readTimeout,
|
readTimeout: readTimeout,
|
||||||
runOnConnect: runOnConnect,
|
runOnConnect: runOnConnect,
|
||||||
protocols: protocols,
|
runOnConnectRestart: runOnConnectRestart,
|
||||||
|
protocols: protocols,
|
||||||
conn: gortsplib.NewConnServer(gortsplib.ConnServerConf{
|
conn: gortsplib.NewConnServer(gortsplib.ConnServerConf{
|
||||||
Conn: nconn,
|
Conn: nconn,
|
||||||
ReadTimeout: readTimeout,
|
ReadTimeout: readTimeout,
|
||||||
|
|
@ -198,11 +201,7 @@ func (c *Client) run() {
|
||||||
|
|
||||||
var onConnectCmd *externalcmd.ExternalCmd
|
var onConnectCmd *externalcmd.ExternalCmd
|
||||||
if c.runOnConnect != "" {
|
if c.runOnConnect != "" {
|
||||||
var err error
|
onConnectCmd = externalcmd.New(c.runOnConnect, c.runOnConnectRestart, "")
|
||||||
onConnectCmd, err = externalcmd.New(c.runOnConnect, "")
|
|
||||||
if err != nil {
|
|
||||||
c.log("ERR: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
@ -939,11 +938,8 @@ func (c *Client) runPlay() bool {
|
||||||
|
|
||||||
var onReadCmd *externalcmd.ExternalCmd
|
var onReadCmd *externalcmd.ExternalCmd
|
||||||
if c.path.Conf().RunOnRead != "" {
|
if c.path.Conf().RunOnRead != "" {
|
||||||
var err error
|
onReadCmd = externalcmd.New(c.path.Conf().RunOnRead,
|
||||||
onReadCmd, err = externalcmd.New(c.path.Conf().RunOnRead, c.path.Name())
|
c.path.Conf().RunOnReadRestart, c.path.Name())
|
||||||
if err != nil {
|
|
||||||
c.log("ERR: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.streamProtocol == gortsplib.StreamProtocolUDP {
|
if c.streamProtocol == gortsplib.StreamProtocolUDP {
|
||||||
|
|
@ -1121,11 +1117,8 @@ func (c *Client) runRecord() bool {
|
||||||
|
|
||||||
var onPublishCmd *externalcmd.ExternalCmd
|
var onPublishCmd *externalcmd.ExternalCmd
|
||||||
if c.path.Conf().RunOnPublish != "" {
|
if c.path.Conf().RunOnPublish != "" {
|
||||||
var err error
|
onPublishCmd = externalcmd.New(c.path.Conf().RunOnPublish,
|
||||||
onPublishCmd, err = externalcmd.New(c.path.Conf().RunOnPublish, c.path.Name())
|
c.path.Conf().RunOnPublishRestart, c.path.Name())
|
||||||
if err != nil {
|
|
||||||
c.log("ERR: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.streamProtocol == gortsplib.StreamProtocolUDP {
|
if c.streamProtocol == gortsplib.StreamProtocolUDP {
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,17 @@ type Parent interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientManager struct {
|
type ClientManager struct {
|
||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
writeTimeout time.Duration
|
writeTimeout time.Duration
|
||||||
runOnConnect string
|
runOnConnect string
|
||||||
protocols map[headers.StreamProtocol]struct{}
|
runOnConnectRestart bool
|
||||||
stats *stats.Stats
|
protocols map[headers.StreamProtocol]struct{}
|
||||||
serverUdpRtp *serverudp.Server
|
stats *stats.Stats
|
||||||
serverUdpRtcp *serverudp.Server
|
serverUdpRtp *serverudp.Server
|
||||||
pathMan *pathman.PathManager
|
serverUdpRtcp *serverudp.Server
|
||||||
serverTcp *servertcp.Server
|
pathMan *pathman.PathManager
|
||||||
parent Parent
|
serverTcp *servertcp.Server
|
||||||
|
parent Parent
|
||||||
|
|
||||||
clients map[*client.Client]struct{}
|
clients map[*client.Client]struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
|
@ -46,6 +47,7 @@ func New(
|
||||||
readTimeout time.Duration,
|
readTimeout time.Duration,
|
||||||
writeTimeout time.Duration,
|
writeTimeout time.Duration,
|
||||||
runOnConnect string,
|
runOnConnect string,
|
||||||
|
runOnConnectRestart bool,
|
||||||
protocols map[headers.StreamProtocol]struct{},
|
protocols map[headers.StreamProtocol]struct{},
|
||||||
stats *stats.Stats,
|
stats *stats.Stats,
|
||||||
serverUdpRtp *serverudp.Server,
|
serverUdpRtp *serverudp.Server,
|
||||||
|
|
@ -55,20 +57,21 @@ func New(
|
||||||
parent Parent) *ClientManager {
|
parent Parent) *ClientManager {
|
||||||
|
|
||||||
cm := &ClientManager{
|
cm := &ClientManager{
|
||||||
readTimeout: readTimeout,
|
readTimeout: readTimeout,
|
||||||
writeTimeout: writeTimeout,
|
writeTimeout: writeTimeout,
|
||||||
runOnConnect: runOnConnect,
|
runOnConnect: runOnConnect,
|
||||||
protocols: protocols,
|
runOnConnectRestart: runOnConnectRestart,
|
||||||
stats: stats,
|
protocols: protocols,
|
||||||
serverUdpRtp: serverUdpRtp,
|
stats: stats,
|
||||||
serverUdpRtcp: serverUdpRtcp,
|
serverUdpRtp: serverUdpRtp,
|
||||||
pathMan: pathMan,
|
serverUdpRtcp: serverUdpRtcp,
|
||||||
serverTcp: serverTcp,
|
pathMan: pathMan,
|
||||||
parent: parent,
|
serverTcp: serverTcp,
|
||||||
clients: make(map[*client.Client]struct{}),
|
parent: parent,
|
||||||
clientClose: make(chan *client.Client),
|
clients: make(map[*client.Client]struct{}),
|
||||||
terminate: make(chan struct{}),
|
clientClose: make(chan *client.Client),
|
||||||
done: make(chan struct{}),
|
terminate: make(chan struct{}),
|
||||||
|
done: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
go cm.run()
|
go cm.run()
|
||||||
|
|
@ -98,6 +101,7 @@ outer:
|
||||||
cm.readTimeout,
|
cm.readTimeout,
|
||||||
cm.writeTimeout,
|
cm.writeTimeout,
|
||||||
cm.runOnConnect,
|
cm.runOnConnect,
|
||||||
|
cm.runOnConnectRestart,
|
||||||
cm.protocols,
|
cm.protocols,
|
||||||
conn,
|
conn,
|
||||||
cm)
|
cm)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ type Conf struct {
|
||||||
RtpPort int `yaml:"rtpPort"`
|
RtpPort int `yaml:"rtpPort"`
|
||||||
RtcpPort int `yaml:"rtcpPort"`
|
RtcpPort int `yaml:"rtcpPort"`
|
||||||
RunOnConnect string `yaml:"runOnConnect"`
|
RunOnConnect string `yaml:"runOnConnect"`
|
||||||
|
RunOnConnectRestart bool `yaml:"runOnConnectRestart"`
|
||||||
ReadTimeout time.Duration `yaml:"readTimeout"`
|
ReadTimeout time.Duration `yaml:"readTimeout"`
|
||||||
WriteTimeout time.Duration `yaml:"writeTimeout"`
|
WriteTimeout time.Duration `yaml:"writeTimeout"`
|
||||||
AuthMethods []string `yaml:"authMethods"`
|
AuthMethods []string `yaml:"authMethods"`
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,13 @@ type PathConf struct {
|
||||||
SourceOnDemand bool `yaml:"sourceOnDemand"`
|
SourceOnDemand bool `yaml:"sourceOnDemand"`
|
||||||
SourceRedirect string `yaml:"sourceRedirect"`
|
SourceRedirect string `yaml:"sourceRedirect"`
|
||||||
RunOnInit string `yaml:"runOnInit"`
|
RunOnInit string `yaml:"runOnInit"`
|
||||||
|
RunOnInitRestart bool `yaml:"runOnInitRestart"`
|
||||||
RunOnDemand string `yaml:"runOnDemand"`
|
RunOnDemand string `yaml:"runOnDemand"`
|
||||||
|
RunOnDemandRestart bool `yaml:"runOnDemandRestart"`
|
||||||
RunOnPublish string `yaml:"runOnPublish"`
|
RunOnPublish string `yaml:"runOnPublish"`
|
||||||
|
RunOnPublishRestart bool `yaml:"runOnPublishRestart"`
|
||||||
RunOnRead string `yaml:"runOnRead"`
|
RunOnRead string `yaml:"runOnRead"`
|
||||||
|
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"`
|
||||||
|
|
|
||||||
|
|
@ -5,29 +5,91 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
restartPause = 2 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExternalCmd struct {
|
type ExternalCmd struct {
|
||||||
cmd *exec.Cmd
|
cmdstr string
|
||||||
|
restart bool
|
||||||
|
pathName string
|
||||||
|
|
||||||
|
// in
|
||||||
|
terminate chan struct{}
|
||||||
|
|
||||||
|
// out
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cmdstr string, pathName string) (*ExternalCmd, error) {
|
func New(cmdstr string, restart bool, pathName string) *ExternalCmd {
|
||||||
|
e := &ExternalCmd{
|
||||||
|
cmdstr: cmdstr,
|
||||||
|
restart: restart,
|
||||||
|
pathName: pathName,
|
||||||
|
terminate: make(chan struct{}),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go e.run()
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExternalCmd) Close() {
|
||||||
|
close(e.terminate)
|
||||||
|
<-e.done
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExternalCmd) run() {
|
||||||
|
defer close(e.done)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !e.runInner() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExternalCmd) runInner() bool {
|
||||||
|
ok := e.runInnerInner()
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !e.restart {
|
||||||
|
<-e.terminate
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.NewTimer(restartPause)
|
||||||
|
defer t.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
return true
|
||||||
|
case <-e.terminate:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ExternalCmd) runInnerInner() bool {
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
// on Windows the shell is not used and command is started directly
|
// on Windows the shell is not used and command is started directly
|
||||||
// variables are replaced manually in order to allow
|
// variables are replaced manually in order to guarantee compatibility
|
||||||
// compatibility with linux commands
|
// with Linux commands
|
||||||
cmdstr = strings.ReplaceAll(cmdstr, "$RTSP_SERVER_PATH", pathName)
|
args := strings.Fields(strings.ReplaceAll(e.cmdstr, "$RTSP_SERVER_PATH", e.pathName))
|
||||||
args := strings.Fields(cmdstr)
|
|
||||||
cmd = exec.Command(args[0], args[1:]...)
|
cmd = exec.Command(args[0], args[1:]...)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
cmd = exec.Command("/bin/sh", "-c", "exec "+cmdstr)
|
cmd = exec.Command("/bin/sh", "-c", "exec "+e.cmdstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// variables are available through environment variables
|
// variables are inserted into the environment
|
||||||
cmd.Env = append(os.Environ(),
|
cmd.Env = append(os.Environ(),
|
||||||
"RTSP_SERVER_PATH="+pathName,
|
"RTSP_SERVER_PATH="+e.pathName,
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
|
|
@ -35,21 +97,28 @@ func New(cmdstr string, pathName string) (*ExternalCmd, error) {
|
||||||
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ExternalCmd{
|
cmdDone := make(chan struct{})
|
||||||
cmd: cmd,
|
go func() {
|
||||||
}, nil
|
defer close(cmdDone)
|
||||||
}
|
cmd.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
func (e *ExternalCmd) Close() {
|
select {
|
||||||
// on Windows it's not possible to send os.Interrupt to a process
|
case <-e.terminate:
|
||||||
// Kill() is the only supported way
|
// on Windows it's not possible to send os.Interrupt to a process
|
||||||
if runtime.GOOS == "windows" {
|
// Kill() is the only supported way
|
||||||
e.cmd.Process.Kill()
|
if runtime.GOOS == "windows" {
|
||||||
} else {
|
cmd.Process.Kill()
|
||||||
e.cmd.Process.Signal(os.Interrupt)
|
} else {
|
||||||
|
cmd.Process.Signal(os.Interrupt)
|
||||||
|
}
|
||||||
|
<-cmdDone
|
||||||
|
return false
|
||||||
|
|
||||||
|
case <-cmdDone:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
e.cmd.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
main.go
6
main.go
|
|
@ -181,8 +181,9 @@ func (p *program) createResources(initial bool) error {
|
||||||
|
|
||||||
if p.clientMan == nil {
|
if p.clientMan == nil {
|
||||||
p.clientMan = clientman.New(p.conf.ReadTimeout, p.conf.WriteTimeout,
|
p.clientMan = clientman.New(p.conf.ReadTimeout, p.conf.WriteTimeout,
|
||||||
p.conf.RunOnConnect, p.conf.ProtocolsParsed, p.stats,
|
p.conf.RunOnConnect, p.conf.RunOnConnectRestart,
|
||||||
p.serverUdpRtp, p.serverUdpRtcp, p.pathMan, p.serverTcp, p)
|
p.conf.ProtocolsParsed, p.stats, p.serverUdpRtp, p.serverUdpRtcp,
|
||||||
|
p.pathMan, p.serverTcp, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.confWatcher == nil {
|
if p.confWatcher == nil {
|
||||||
|
|
@ -295,6 +296,7 @@ func (p *program) reloadConf() error {
|
||||||
conf.ReadTimeout != p.conf.ReadTimeout ||
|
conf.ReadTimeout != p.conf.ReadTimeout ||
|
||||||
conf.WriteTimeout != p.conf.WriteTimeout ||
|
conf.WriteTimeout != p.conf.WriteTimeout ||
|
||||||
conf.RunOnConnect != p.conf.RunOnConnect ||
|
conf.RunOnConnect != p.conf.RunOnConnect ||
|
||||||
|
conf.RunOnConnectRestart != p.conf.RunOnConnectRestart ||
|
||||||
!reflect.DeepEqual(conf.ProtocolsParsed, p.conf.ProtocolsParsed) {
|
!reflect.DeepEqual(conf.ProtocolsParsed, p.conf.ProtocolsParsed) {
|
||||||
closeClientMan = true
|
closeClientMan = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
path/path.go
14
path/path.go
|
|
@ -223,11 +223,8 @@ func (pa *Path) run() {
|
||||||
|
|
||||||
if pa.conf.RunOnInit != "" {
|
if pa.conf.RunOnInit != "" {
|
||||||
pa.Log("starting on init command")
|
pa.Log("starting on init command")
|
||||||
var err error
|
pa.onInitCmd = externalcmd.New(pa.conf.RunOnInit,
|
||||||
pa.onInitCmd, err = externalcmd.New(pa.conf.RunOnInit, pa.name)
|
pa.conf.RunOnInitRestart, pa.name)
|
||||||
if err != nil {
|
|
||||||
pa.Log("ERR: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tickerCheck := time.NewTicker(pathCheckPeriod)
|
tickerCheck := time.NewTicker(pathCheckPeriod)
|
||||||
|
|
@ -516,11 +513,8 @@ func (pa *Path) onClientDescribe(c *client.Client) {
|
||||||
if pa.onDemandCmd == nil { // start if needed
|
if pa.onDemandCmd == nil { // start if needed
|
||||||
pa.Log("starting on demand command")
|
pa.Log("starting on demand command")
|
||||||
pa.lastDescribeActivation = time.Now()
|
pa.lastDescribeActivation = time.Now()
|
||||||
var err error
|
pa.onDemandCmd = externalcmd.New(pa.conf.RunOnDemand,
|
||||||
pa.onDemandCmd, err = externalcmd.New(pa.conf.RunOnDemand, pa.name)
|
pa.conf.RunOnDemandRestart, pa.name)
|
||||||
if err != nil {
|
|
||||||
pa.Log("ERR: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pa.clients[c] = clientStateWaitingDescribe
|
pa.clients[c] = clientStateWaitingDescribe
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,6 @@ writeTimeout: 5s
|
||||||
# to enforce security).
|
# to enforce security).
|
||||||
authMethods: [basic, digest]
|
authMethods: [basic, digest]
|
||||||
|
|
||||||
# command to run when a client connects.
|
|
||||||
# this is terminated with SIGINT when a client disconnects.
|
|
||||||
runOnConnect:
|
|
||||||
|
|
||||||
# enable Prometheus-compatible metrics on port 9998.
|
# enable Prometheus-compatible metrics on port 9998.
|
||||||
metrics: no
|
metrics: no
|
||||||
# enable pprof on port 9999 to monitor performances.
|
# enable pprof on port 9999 to monitor performances.
|
||||||
|
|
@ -31,6 +27,11 @@ logDestinations: [stdout]
|
||||||
# if "file" is in logDestinations, this is the file that will receive the logs.
|
# if "file" is in logDestinations, this is the file that will receive the logs.
|
||||||
logFile: rtsp-simple-server.log
|
logFile: rtsp-simple-server.log
|
||||||
|
|
||||||
|
# command to run when a client connects to the server.
|
||||||
|
# this is terminated with SIGINT when a client disconnects from the server.
|
||||||
|
runOnConnect:
|
||||||
|
runOnConnectRestart: no
|
||||||
|
|
||||||
# these settings are path-dependent.
|
# these settings are path-dependent.
|
||||||
# it's possible to use regular expressions by using a tilde as prefix.
|
# it's possible to use regular expressions by using a tilde as prefix.
|
||||||
# for example, "~^(test1|test2)$" will match both "test1" and "test2".
|
# for example, "~^(test1|test2)$" will match both "test1" and "test2".
|
||||||
|
|
@ -57,28 +58,6 @@ paths:
|
||||||
# redirected to.
|
# redirected to.
|
||||||
sourceRedirect:
|
sourceRedirect:
|
||||||
|
|
||||||
# command to run when this path is loaded by the program.
|
|
||||||
# this can be used, for example, to publish a stream and keep it always opened.
|
|
||||||
# this is terminated with SIGINT when the program closes.
|
|
||||||
# the path name is available in the RTSP_SERVER_PATH variable.
|
|
||||||
runOnInit:
|
|
||||||
|
|
||||||
# command to run when this path is requested.
|
|
||||||
# this can be used, for example, to publish a stream on demand.
|
|
||||||
# this is terminated with SIGINT when the path is not requested anymore.
|
|
||||||
# the path name is available in the RTSP_SERVER_PATH variable.
|
|
||||||
runOnDemand:
|
|
||||||
|
|
||||||
# command to run when a client starts publishing.
|
|
||||||
# this is terminated with SIGINT when a client stops publishing.
|
|
||||||
# the path name is available in the RTSP_SERVER_PATH variable.
|
|
||||||
runOnPublish:
|
|
||||||
|
|
||||||
# command to run when a clients starts reading.
|
|
||||||
# this is terminated with SIGINT when a client stops reading.
|
|
||||||
# the path name is available in the RTSP_SERVER_PATH variable.
|
|
||||||
runOnRead:
|
|
||||||
|
|
||||||
# username required to publish.
|
# username required to publish.
|
||||||
publishUser:
|
publishUser:
|
||||||
# password required to publish.
|
# password required to publish.
|
||||||
|
|
@ -92,3 +71,29 @@ paths:
|
||||||
readPass:
|
readPass:
|
||||||
# ips or networks (x.x.x.x/24) allowed to read.
|
# ips or networks (x.x.x.x/24) allowed to read.
|
||||||
readIps: []
|
readIps: []
|
||||||
|
|
||||||
|
# command to run when this path is loaded by the program.
|
||||||
|
# this can be used, for example, to publish a stream and keep it always opened.
|
||||||
|
# this is terminated with SIGINT when the program closes.
|
||||||
|
# the path name is available in the RTSP_SERVER_PATH variable.
|
||||||
|
runOnInit:
|
||||||
|
runOnInitRestart: no
|
||||||
|
|
||||||
|
# command to run when this path is requested.
|
||||||
|
# this can be used, for example, to publish a stream on demand.
|
||||||
|
# this is terminated with SIGINT when the path is not requested anymore.
|
||||||
|
# the path name is available in the RTSP_SERVER_PATH variable.
|
||||||
|
runOnDemand:
|
||||||
|
runOnDemandRestart: no
|
||||||
|
|
||||||
|
# command to run when a client starts publishing.
|
||||||
|
# this is terminated with SIGINT when a client stops publishing.
|
||||||
|
# the path name is available in the RTSP_SERVER_PATH variable.
|
||||||
|
runOnPublish:
|
||||||
|
runOnPublishRestart: no
|
||||||
|
|
||||||
|
# command to run when a clients starts reading.
|
||||||
|
# this is terminated with SIGINT when a client stops reading.
|
||||||
|
# the path name is available in the RTSP_SERVER_PATH variable.
|
||||||
|
runOnRead:
|
||||||
|
runOnReadRestart: no
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue