feat: Add signal related params to exec

This commit is contained in:
dadav
2024-01-10 20:20:00 +01:00
parent 4b62a6e34f
commit 152719441e
6 changed files with 358 additions and 156 deletions
+100 -88
View File
@@ -37,60 +37,60 @@ Ultimate camera streaming application with support RTSP, WebRTC, HomeKit, FFmpeg
---
* [Fast start](#fast-start)
* [go2rtc: Binary](#go2rtc-binary)
* [go2rtc: Docker](#go2rtc-docker)
* [go2rtc: Home Assistant Add-on](#go2rtc-home-assistant-add-on)
* [go2rtc: Home Assistant Integration](#go2rtc-home-assistant-integration)
* [go2rtc: Dev version](#go2rtc-dev-version)
* [Configuration](#configuration)
* [Module: Streams](#module-streams)
* [Two way audio](#two-way-audio)
* [Source: RTSP](#source-rtsp)
* [Source: RTMP](#source-rtmp)
* [Source: HTTP](#source-http)
* [Source: ONVIF](#source-onvif)
* [Source: FFmpeg](#source-ffmpeg)
* [Source: FFmpeg Device](#source-ffmpeg-device)
* [Source: Exec](#source-exec)
* [Source: Echo](#source-echo)
* [Source: Expr](#source-expr)
* [Source: HomeKit](#source-homekit)
* [Source: Bubble](#source-bubble)
* [Source: DVRIP](#source-dvrip)
* [Source: Tapo](#source-tapo)
* [Source: Kasa](#source-kasa)
* [Source: GoPro](#source-gopro)
* [Source: Ivideon](#source-ivideon)
* [Source: Hass](#source-hass)
* [Source: ISAPI](#source-isapi)
* [Source: Nest](#source-nest)
* [Source: Roborock](#source-roborock)
* [Source: WebRTC](#source-webrtc)
* [Source: WebTorrent](#source-webtorrent)
* [Incoming sources](#incoming-sources)
* [Stream to camera](#stream-to-camera)
* [Publish stream](#publish-stream)
* [Module: API](#module-api)
* [Module: RTSP](#module-rtsp)
* [Module: RTMP](#module-rtmp)
* [Module: WebRTC](#module-webrtc)
* [Module: HomeKit](#module-homekit)
* [Module: WebTorrent](#module-webtorrent)
* [Module: ngrok](#module-ngrok)
* [Module: Hass](#module-hass)
* [Module: MP4](#module-mp4)
* [Module: HLS](#module-hls)
* [Module: MJPEG](#module-mjpeg)
* [Module: Log](#module-log)
* [Security](#security)
* [Codecs filters](#codecs-filters)
* [Codecs madness](#codecs-madness)
* [Codecs negotiation](#codecs-negotiation)
* [Projects using go2rtc](#projects-using-go2rtc)
* [Camera experience](#cameras-experience)
* [TIPS](#tips)
* [FAQ](#faq)
- [Fast start](#fast-start)
- [go2rtc: Binary](#go2rtc-binary)
- [go2rtc: Docker](#go2rtc-docker)
- [go2rtc: Home Assistant Add-on](#go2rtc-home-assistant-add-on)
- [go2rtc: Home Assistant Integration](#go2rtc-home-assistant-integration)
- [go2rtc: Dev version](#go2rtc-dev-version)
- [Configuration](#configuration)
- [Module: Streams](#module-streams)
- [Two way audio](#two-way-audio)
- [Source: RTSP](#source-rtsp)
- [Source: RTMP](#source-rtmp)
- [Source: HTTP](#source-http)
- [Source: ONVIF](#source-onvif)
- [Source: FFmpeg](#source-ffmpeg)
- [Source: FFmpeg Device](#source-ffmpeg-device)
- [Source: Exec](#source-exec)
- [Source: Echo](#source-echo)
- [Source: Expr](#source-expr)
- [Source: HomeKit](#source-homekit)
- [Source: Bubble](#source-bubble)
- [Source: DVRIP](#source-dvrip)
- [Source: Tapo](#source-tapo)
- [Source: Kasa](#source-kasa)
- [Source: GoPro](#source-gopro)
- [Source: Ivideon](#source-ivideon)
- [Source: Hass](#source-hass)
- [Source: ISAPI](#source-isapi)
- [Source: Nest](#source-nest)
- [Source: Roborock](#source-roborock)
- [Source: WebRTC](#source-webrtc)
- [Source: WebTorrent](#source-webtorrent)
- [Incoming sources](#incoming-sources)
- [Stream to camera](#stream-to-camera)
- [Publish stream](#publish-stream)
- [Module: API](#module-api)
- [Module: RTSP](#module-rtsp)
- [Module: RTMP](#module-rtmp)
- [Module: WebRTC](#module-webrtc)
- [Module: HomeKit](#module-homekit)
- [Module: WebTorrent](#module-webtorrent)
- [Module: ngrok](#module-ngrok)
- [Module: Hass](#module-hass)
- [Module: MP4](#module-mp4)
- [Module: HLS](#module-hls)
- [Module: MJPEG](#module-mjpeg)
- [Module: Log](#module-log)
- [Security](#security)
- [Codecs filters](#codecs-filters)
- [Codecs madness](#codecs-madness)
- [Codecs negotiation](#codecs-negotiation)
- [Projects using go2rtc](#projects-using-go2rtc)
- [Camera experience](#cameras-experience)
- [TIPS](#tips)
- [FAQ](#faq)
## Fast start
@@ -152,7 +152,7 @@ Latest, but maybe unstable version:
## Configuration
- by default go2rtc will search `go2rtc.yaml` in the current work dirrectory
- by default go2rtc will search `go2rtc.yaml` in the current work directory
- `api` server will start on default **1984 port** (TCP)
- `rtsp` server will start on default **8554 port** (TCP)
- `webrtc` will use port **8555** (TCP/UDP) for connections
@@ -305,7 +305,7 @@ streams:
#### Source: ONVIF
*[New in v1.5.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.5.0)*
_[New in v1.5.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.5.0)_
The source is not very useful if you already know RTSP and snapshot links for your camera. But it can be useful if you don't.
@@ -399,12 +399,23 @@ streams:
#### Source: Exec
Exec source can run any external application and expect data from it. Two transports are supported - **pipe** (*from [v1.5.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.5.0)*) and **RTSP**.
Exec source can run any external application and expect data from it. Two transports are supported - **pipe** (_from [v1.5.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.5.0)_) and **RTSP**.
If you want to use **RTSP** transport - the command must contain the `{output}` argument in any place. On launch, it will be replaced by the local address of the RTSP server.
**pipe** reads data from app stdout in different formats: **MJPEG**, **H.264/H.265 bitstream**, **MPEG-TS**.
Pipe commands support two parameters:
- **killsignal**: Signal which will be send to stop the process (default: sigkill)
- **killtimeout**: Time in seconds after the process will killed with sigkill (default: 5)
The **killtimeout** parameter is only relevant if **killsignal** is not sigkill.
Setting **killtimeout** to a negative number (or zero) will result in an immediate SIGKILL.
See `man 7 signal` to get a full list of all the signals.
Format: `exec:{command}#{param1}#{param2}`
The source can be used with:
- [FFmpeg](https://ffmpeg.org/) - go2rtc ffmpeg source just a shortcut to exec source
@@ -417,6 +428,7 @@ streams:
stream: exec:ffmpeg -re -i /media/BigBuckBunny.mp4 -c copy -rtsp_transport tcp -f rtsp {output}
picam_h264: exec:libcamera-vid -t 0 --inline -o -
picam_mjpeg: exec:libcamera-vid -t 0 --codec mjpeg -o -
canon: exec:gphoto2 --capture-movie --stdout#killsignal=sigint
```
#### Source: Echo
@@ -434,7 +446,7 @@ streams:
#### Source: Expr
*[New in v1.8.2](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.2)*
_[New in v1.8.2](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.2)_
Like `echo` source, but uses the built-in [expr](https://github.com/antonmedv/expr) expression language ([read more](https://github.com/AlexxIT/go2rtc/blob/master/internal/expr/README.md)).
@@ -473,7 +485,7 @@ RTSP link with "normal" audio for any player: `rtsp://192.168.1.123:8554/aqara_g
#### Source: Bubble
*[New in v1.6.1](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.1)*
_[New in v1.6.1](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.1)_
Other names: [ESeeCloud](http://www.eseecloud.com/), [dvr163](http://help.dvr163.com/).
@@ -487,7 +499,7 @@ streams:
#### Source: DVRIP
*[New in v1.2.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.2.0)*
_[New in v1.2.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.2.0)_
Other names: DVR-IP, NetSurveillance, Sofia protocol (NETsurveillance ActiveX plugin XMeye SDK).
@@ -507,7 +519,7 @@ streams:
#### Source: Tapo
*[New in v1.2.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.2.0)*
_[New in v1.2.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.2.0)_
[TP-Link Tapo](https://www.tapo.com/) proprietary camera protocol with **two way audio** support.
@@ -533,7 +545,7 @@ echo -n "cloud password" | shasum -a 256 | awk '{print toupper($0)}'
#### Source: Kasa
*[New in v1.7.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.7.0)*
_[New in v1.7.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.7.0)_
[TP-Link Kasa](https://www.kasasmart.com/) non-standard protocol [more info](https://medium.com/@hu3vjeen/reverse-engineering-tp-link-kc100-bac4641bf1cd).
@@ -544,7 +556,7 @@ streams:
#### Source: GoPro
*[New in v1.8.3](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.3)*
_[New in v1.8.3](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.3)_
Support streaming from [GoPro](https://gopro.com/) cameras, connected via USB or Wi-Fi to Linux, Mac, Windows. [Read more](https://github.com/AlexxIT/go2rtc/tree/master/internal/gopro).
@@ -575,7 +587,7 @@ streams:
aqara_g3: hass:Camera-Hub-G3-AB12
```
**WebRTC Cameras** (*from [v1.6.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.0)*)
**WebRTC Cameras** (_from [v1.6.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.0)_)
Any cameras in WebRTC format are supported. But at the moment Home Assistant only supports some [Nest](https://www.home-assistant.io/integrations/nest/) cameras in this fomat.
@@ -595,7 +607,7 @@ By default, the Home Assistant API does not allow you to get dynamic RTSP link t
#### Source: ISAPI
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
This source type support only backchannel audio for Hikvision ISAPI protocol. So it should be used as second source in addition to the RTSP protocol.
@@ -608,7 +620,7 @@ streams:
#### Source: Nest
*[New in v1.6.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.0)*
_[New in v1.6.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.0)_
Currently only WebRTC cameras are supported. Stream reconnects every 5 minutes.
@@ -621,7 +633,7 @@ streams:
#### Source: Roborock
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
This source type support Roborock vacuums with cameras. Known working models:
@@ -634,7 +646,7 @@ If you have graphic pin for your vacuum - add it as numeric pin (lines: 123, 456
#### Source: WebRTC
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
This source type support four connection formats.
@@ -646,15 +658,15 @@ This source type support four connection formats.
This format is only supported in go2rtc. Unlike WHEP it supports asynchronous WebRTC connection and two way audio.
**openipc** (*from [v1.7.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.7.0)*)
**openipc** (_from [v1.7.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.7.0)_)
Support connection to [OpenIPC](https://openipc.org/) cameras.
**wyze** (*from [v1.6.1](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.1)*)
**wyze** (_from [v1.6.1](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.1)_)
Supports connection to [Wyze](https://www.wyze.com/) cameras, using WebRTC protocol. You can use [docker-wyze-bridge](https://github.com/mrlt8/docker-wyze-bridge) project to get connection credentials.
**kinesis** (*from [v1.6.1](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.1)*)
**kinesis** (_from [v1.6.1](https://github.com/AlexxIT/go2rtc/releases/tag/v1.6.1)_)
Supports [Amazon Kinesis Video Streams](https://aws.amazon.com/kinesis/video-streams/), using WebRTC protocol. You need to specify signalling WebSocket URL with all credentials in query params, `client_id` and `ice_servers` list in [JSON format](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer).
@@ -671,7 +683,7 @@ streams:
#### Source: WebTorrent
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
This source can get a stream from another go2rtc via [WebTorrent](#module-webtorrent) protocol.
@@ -711,7 +723,7 @@ By default, go2rtc establishes a connection to the source when any client reques
#### Incoming: Browser
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
You can turn the browser of any PC or mobile into an IP-camera with support video and two way audio. Or even broadcast your PC screen:
@@ -723,7 +735,7 @@ You can turn the browser of any PC or mobile into an IP-camera with support vide
#### Incoming: WebRTC/WHIP
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
You can use **OBS Studio** or any other broadcast software with [WHIP](https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html) protocol support. This standard has not yet been approved. But you can download OBS Studio [dev version](https://github.com/obsproject/obs-studio/actions/runs/3969201209):
@@ -731,7 +743,7 @@ You can use **OBS Studio** or any other broadcast software with [WHIP](https://w
#### Stream to camera
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
go2rtc support play audio files (ex. music or [TTS](https://www.home-assistant.io/integrations/#text-to-speech)) and live streams (ex. radio) on cameras with [two way audio](#two-way-audio) support (RTSP/ONVIF cameras, TP-Link Tapo, Hikvision ISAPI, Roborock vacuums, any Browser).
@@ -753,7 +765,7 @@ POST http://localhost:1984/api/streams?dst=camera1&src=ffmpeg:http://example.com
### Publish stream
*[New in v1.8.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.0)*
_[New in v1.8.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.0)_
You can publish any stream to streaming services (YouTube, Telegram, etc.) via RTMP/RTMPS. Important:
@@ -852,7 +864,7 @@ Read more about [codecs filters](#codecs-filters).
### Module: RTMP
*[New in v1.8.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.0)*
_[New in v1.8.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.8.0)_
You can get any stream as RTMP-stream: `rtmp://192.168.1.123/{stream_name}`. Only H264/AAC codecs supported right now.
@@ -932,7 +944,7 @@ webrtc:
### Module: HomeKit
*[New in v1.7.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.7.0)*
_[New in v1.7.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.7.0)_
HomeKit module can work in two modes:
@@ -986,7 +998,7 @@ homekit:
### Module: WebTorrent
*[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)*
_[New in v1.3.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.3.0)_
This module support:
@@ -1118,7 +1130,7 @@ API examples:
- MP4 snapshot: `http://192.168.1.123:1984/api/frame.mp4?src=camera1` (H264, H265)
- MP4 stream: `http://192.168.1.123:1984/api/stream.mp4?src=camera1` (H264, H265, AAC)
- MP4 file: `http://192.168.1.123:1984/api/stream.mp4?src=camera1` (H264, H265*, AAC, OPUS, MP3, PCMA, PCMU, PCM)
- MP4 file: `http://192.168.1.123:1984/api/stream.mp4?src=camera1` (H264, H265\*, AAC, OPUS, MP3, PCMA, PCMU, PCM)
- You can use `mp4`, `mp4=flac` and `mp4=all` param for codec filters
- You can use `duration` param in seconds (ex. `duration=15`)
- You can use `filename` param (ex. `filename=record.mp4`)
@@ -1131,7 +1143,7 @@ Read more about [codecs filters](#codecs-filters).
### Module: HLS
*[New in v1.1.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.1.0)*
_[New in v1.1.0](https://github.com/AlexxIT/go2rtc/releases/tag/v1.1.0)_
[HLS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) is the worst technology for real-time streaming. It can only be useful on devices that do not support more modern technology, like [WebRTC](#module-webrtc), [MSE/MP4](#module-mp4).
@@ -1240,14 +1252,14 @@ Some examples:
`AVC/H.264` video can be played almost anywhere. But `HEVC/H.265` has a lot of limitations in supporting with different devices and browsers. It's all about patents and money, you can't do anything about it.
| Device | WebRTC | MSE | HTTP* | HLS |
|--------------------------------------------------------------------------|-----------------------------------------|-----------------------------------------|----------------------------------------------|-----------------------------|
| *latency* | best | medium | bad | bad |
| Device | WebRTC | MSE | HTTP\* | HLS |
| ------------------------------------------------------------------------ | ---------------------------------------- | --------------------------------------- | -------------------------------------------- | ---------------------------- |
| _latency_ | best | medium | bad | bad |
| - Desktop Chrome 107+ <br/> - Desktop Edge <br/> - Android Chrome 107+ | H264 <br/> PCMU, PCMA <br/> OPUS | H264, H265* <br/> AAC, FLAC* <br/> OPUS | H264, H265* <br/> AAC, FLAC* <br/> OPUS, MP3 | no |
| Desktop Firefox | H264 <br/> PCMU, PCMA <br/> OPUS | H264 <br/> AAC, FLAC* <br/> OPUS | H264 <br/> AAC, FLAC* <br/> OPUS | no |
| - Desktop Safari 14+ <br/> - iPad Safari 14+ <br/> - iPhone Safari 17.1+ | H264, H265* <br/> PCMU, PCMA <br/> OPUS | H264, H265 <br/> AAC, FLAC* | **no!** | H264, H265 <br/> AAC, FLAC* |
| iPhone Safari 14+ | H264, H265* <br/> PCMU, PCMA <br/> OPUS | **no!** | **no!** | H264, H265 <br/> AAC, FLAC* |
| macOS [Hass App][1] | no | no | no | H264, H265 <br/> AAC, FLAC* |
| Desktop Firefox | H264 <br/> PCMU, PCMA <br/> OPUS | H264 <br/> AAC, FLAC\* <br/> OPUS | H264 <br/> AAC, FLAC\* <br/> OPUS | no |
| - Desktop Safari 14+ <br/> - iPad Safari 14+ <br/> - iPhone Safari 17.1+ | H264, H265\* <br/> PCMU, PCMA <br/> OPUS | H264, H265 <br/> AAC, FLAC\* | **no!** | H264, H265 <br/> AAC, FLAC\* |
| iPhone Safari 14+ | H264, H265\* <br/> PCMU, PCMA <br/> OPUS | **no!** | **no!** | H264, H265 <br/> AAC, FLAC\* |
| macOS [Hass App][1] | no | no | no | H264, H265 <br/> AAC, FLAC\* |
[1]: https://apps.apple.com/app/home-assistant/id1099568401
+20 -7
View File
@@ -20,6 +20,12 @@ import (
"github.com/rs/zerolog"
)
type Params struct {
KillSignal os.Signal
Command string
KillTimeout time.Duration
}
func Init() {
rtsp.HandleFunc(func(conn *pkg.Conn) bool {
waitersMu.Lock()
@@ -47,7 +53,12 @@ func Init() {
func execHandle(url string) (core.Producer, error) {
var path string
args := shell.QuoteSplit(url[5:]) // remove `exec:`
params, err := parseParams(url)
if err != nil {
return nil, err
}
args := shell.QuoteSplit(params.Command[5:]) // remove `exec:`
for i, arg := range args {
if arg == "{output}" {
if rtsp.Port == "" {
@@ -67,14 +78,14 @@ func execHandle(url string) (core.Producer, error) {
}
if path == "" {
return handlePipe(url, cmd)
return handlePipe(url, cmd, params)
}
return handleRTSP(url, path, cmd)
}
func handlePipe(url string, cmd *exec.Cmd) (core.Producer, error) {
r, err := PipeCloser(cmd)
func handlePipe(_ string, cmd *exec.Cmd, params *Params) (core.Producer, error) {
r, err := PipeCloser(cmd, params)
if err != nil {
return nil, err
}
@@ -144,6 +155,8 @@ func handleRTSP(url, path string, cmd *exec.Cmd) (core.Producer, error) {
// internal
var log zerolog.Logger
var waiters = map[string]chan core.Producer{}
var waitersMu sync.Mutex
var (
log zerolog.Logger
waiters = map[string]chan core.Producer{}
waitersMu sync.Mutex
)
+34
View File
@@ -0,0 +1,34 @@
//go:build !linux
package exec
import (
"fmt"
"net/url"
"runtime"
"strings"
"github.com/AlexxIT/go2rtc/internal/streams"
)
func parseParams(s string) (*Params, error) {
args := &Params{
Command: s,
}
var query url.Values
if i := strings.IndexByte(s, '#'); i > 0 {
query = streams.ParseQuery(s[i+1:])
args.Command = s[:i]
}
if _, ok := query["killsignal"]; ok {
return nil, fmt.Errorf("killsignal is not supported this %s", runtime.GOOS)
}
if _, ok := query["killtimeout"]; ok {
return nil, fmt.Errorf("killtimeout is not supported in %s", runtime.GOOS)
}
return args, nil
}
+88
View File
@@ -0,0 +1,88 @@
package exec
import (
"fmt"
"net/url"
"os"
"strconv"
"strings"
"syscall"
"time"
"github.com/AlexxIT/go2rtc/internal/streams"
)
func parseParams(s string) (*Params, error) {
args := &Params{
KillSignal: syscall.SIGKILL,
KillTimeout: 5 * time.Second,
Command: s,
}
var query url.Values
if i := strings.IndexByte(s, '#'); i > 0 {
query = streams.ParseQuery(s[i+1:])
args.Command = s[:i]
}
if val, ok := query["killsignal"]; ok {
if sig, err := parseSignal(val[0]); err == nil {
args.KillSignal = sig
} else {
return nil, fmt.Errorf("could not parse killsignal param (%s)", val[0])
}
}
if val, ok := query["killtimeout"]; ok {
if i, err := strconv.Atoi(val[0]); err == nil {
args.KillTimeout = time.Duration(i) * time.Second
} else {
return nil, fmt.Errorf("could not convert killtimeout param (%s) to int", val[0])
}
}
return args, nil
}
func parseSignal(signalString string) (os.Signal, error) {
signalMap := map[string]os.Signal{
"sighup": syscall.SIGHUP,
"sigint": syscall.SIGINT,
"sigquit": syscall.SIGQUIT,
"sigill": syscall.SIGILL,
"sigtrap": syscall.SIGTRAP,
"sigabrt": syscall.SIGABRT,
"sigbus": syscall.SIGBUS,
"sigfpe": syscall.SIGFPE,
"sigkill": syscall.SIGKILL,
"sigusr1": syscall.SIGUSR1,
"sigsegv": syscall.SIGSEGV,
"sigusr2": syscall.SIGUSR2,
"sigpipe": syscall.SIGPIPE,
"sigalrm": syscall.SIGALRM,
"sigterm": syscall.SIGTERM,
"sigchld": syscall.SIGCHLD,
"sigcont": syscall.SIGCONT,
"sigstop": syscall.SIGSTOP,
"sigtstp": syscall.SIGTSTP,
"sigttin": syscall.SIGTTIN,
"sigttou": syscall.SIGTTOU,
"sigurg": syscall.SIGURG,
"sigxcpu": syscall.SIGXCPU,
"sigxfsz": syscall.SIGXFSZ,
"sigvtalrm": syscall.SIGVTALRM,
"sigprof": syscall.SIGPROF,
"sigwinch": syscall.SIGWINCH,
"sigio": syscall.SIGIO,
"sigpoll": syscall.SIGPOLL,
"sigpwr": syscall.SIGPWR,
"sigsys": syscall.SIGSYS,
}
signalValue, ok := signalMap[strings.ToLower(signalString)]
if !ok {
return nil, fmt.Errorf("invalid signal: %s", signalString)
}
return signalValue, nil
}
+10 -3
View File
@@ -1,3 +1,5 @@
//go:build !linux
package exec
import (
@@ -9,22 +11,27 @@ import (
)
// PipeCloser - return StdoutPipe that Kill cmd on Close call
func PipeCloser(cmd *exec.Cmd) (io.ReadCloser, error) {
func PipeCloser(cmd *exec.Cmd, params *Params) (io.ReadCloser, error) {
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
// add buffer for pipe reader to reduce syscall
return pipeCloser{bufio.NewReaderSize(stdout, core.BufferSize), stdout, cmd}, nil
return pipeCloser{bufio.NewReaderSize(stdout, core.BufferSize), stdout, cmd, params}, nil
}
type pipeCloser struct {
io.Reader
io.Closer
cmd *exec.Cmd
params *Params
}
func (p pipeCloser) Close() error {
return core.Any(p.Closer.Close(), p.cmd.Process.Kill(), p.cmd.Wait())
finished := make(chan bool)
err := core.Any(p.Closer.Close(), p.cmd.Process.Kill(), p.cmd.Wait())
finished <- true
return err
}
+48
View File
@@ -0,0 +1,48 @@
package exec
import (
"bufio"
"io"
"os/exec"
"syscall"
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
)
// PipeCloser - return StdoutPipe that Kill cmd on Close call
func PipeCloser(cmd *exec.Cmd, params *Params) (io.ReadCloser, error) {
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
// add buffer for pipe reader to reduce syscall
return pipeCloser{bufio.NewReaderSize(stdout, core.BufferSize), stdout, cmd, params}, nil
}
type pipeCloser struct {
io.Reader
io.Closer
cmd *exec.Cmd
params *Params
}
func (p pipeCloser) Close() error {
finished := make(chan bool)
if p.params.KillSignal != syscall.SIGKILL {
go func() {
select {
case <-time.After(p.params.KillTimeout):
p.cmd.Process.Kill()
break
case <-finished:
break
}
}()
}
err := core.Any(p.Closer.Close(), p.cmd.Process.Signal(p.params.KillSignal), p.cmd.Wait())
finished <- true
return err
}