diff --git a/README.md b/README.md index a34b5a5a..c803b7a3 100644 --- a/README.md +++ b/README.md @@ -462,6 +462,7 @@ Pipe commands support parameters (format: `exec:{command}#{param1}#{param2}`): - `killsignal` - signal which will be sent to stop the process (numeric form) - `killtimeout` - time in seconds for forced termination with sigkill - `backchannel` - enable backchannel for two-way audio +- `starttimeout` - time in seconds for waiting first byte from RTSP ```yaml streams: diff --git a/internal/exec/exec.go b/internal/exec/exec.go index bf99168f..e428aefb 100644 --- a/internal/exec/exec.go +++ b/internal/exec/exec.go @@ -88,6 +88,7 @@ func execHandle(rawURL string) (prod core.Producer, err error) { } if allowPaths != nil && !slices.Contains(allowPaths, cmd.Args[0]) { + _ = cmd.Close() return nil, errors.New("exec: bin not in allow_paths: " + cmd.Args[0]) } @@ -107,10 +108,17 @@ func execHandle(rawURL string) (prod core.Producer, err error) { return pcm.NewBackchannel(cmd, query.Get("audio")) } + var timeout time.Duration + if s := query.Get("starttimeout"); s != "" { + timeout = time.Duration(core.Atoi(s)) * time.Second + } else { + timeout = 30 * time.Second + } + if path == "" { prod, err = handlePipe(rawURL, cmd) } else { - prod, err = handleRTSP(rawURL, cmd, path) + prod, err = handleRTSP(rawURL, cmd, path, timeout) } if err != nil { @@ -159,7 +167,7 @@ func handlePipe(source string, cmd *shell.Command) (core.Producer, error) { return prod, nil } -func handleRTSP(source string, cmd *shell.Command, path string) (core.Producer, error) { +func handleRTSP(source string, cmd *shell.Command, path string, timeout time.Duration) (core.Producer, error) { if log.Trace().Enabled() { cmd.Stdout = os.Stdout } @@ -185,11 +193,11 @@ func handleRTSP(source string, cmd *shell.Command, path string) (core.Producer, return nil, err } - timeout := time.NewTimer(30 * time.Second) - defer timeout.Stop() + timer := time.NewTimer(timeout) + defer timer.Stop() select { - case <-timeout.C: + case <-timer.C: // haven't received data from app in timeout log.Error().Str("source", source).Msg("[exec] timeout") return nil, errors.New("exec: timeout")