mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 17:40:46 -04:00
whip whep whap
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ENV_FILE="${WHIP_ENV_FILE:-/var/lib/roverd/whip.env}"
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "Environment file ${ENV_FILE} missing; cannot publish" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
|
||||
: "${WHIP_URL:?WHIP_URL not set in ${ENV_FILE}}"
|
||||
|
||||
VIDEO_WIDTH="${VIDEO_WIDTH:-1280}"
|
||||
VIDEO_HEIGHT="${VIDEO_HEIGHT:-720}"
|
||||
VIDEO_FPS="${VIDEO_FPS:-30}"
|
||||
VIDEO_BITRATE="${VIDEO_BITRATE:-3000000}"
|
||||
|
||||
LIBCAMERA_BIN="${LIBCAMERA_BIN:-/usr/bin/libcamera-vid}"
|
||||
FFMPEG_BIN="${FFMPEG_BIN:-/usr/bin/ffmpeg}"
|
||||
|
||||
if [[ ! -x "$LIBCAMERA_BIN" ]]; then
|
||||
echo "libcamera-vid not found at ${LIBCAMERA_BIN}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -x "$FFMPEG_BIN" ]]; then
|
||||
echo "ffmpeg not found at ${FFMPEG_BIN}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run_pipeline() {
|
||||
"${LIBCAMERA_BIN}" \
|
||||
--inline \
|
||||
--timeout 0 \
|
||||
--width "${VIDEO_WIDTH}" \
|
||||
--height "${VIDEO_HEIGHT}" \
|
||||
--framerate "${VIDEO_FPS}" \
|
||||
--bitrate "${VIDEO_BITRATE}" \
|
||||
--codec h264 \
|
||||
--denoise cdn_off \
|
||||
--nopreview \
|
||||
--output - |
|
||||
"${FFMPEG_BIN}" \
|
||||
-hide_banner \
|
||||
-loglevel warning \
|
||||
-f h264 \
|
||||
-i pipe:0 \
|
||||
-c:v copy \
|
||||
-an \
|
||||
-f whip \
|
||||
"${WHIP_URL}"
|
||||
}
|
||||
|
||||
while true; do
|
||||
if run_pipeline; then
|
||||
exit 0
|
||||
fi
|
||||
echo "WHIP publisher exited, restarting in 2s..." >&2
|
||||
sleep 2
|
||||
done
|
||||
+34
-88
@@ -6,8 +6,6 @@ set -euo pipefail
|
||||
|
||||
BINARY_SRC="dist/roverd"
|
||||
CONFIG_SRC="pi/roverd/roverd.sample.yaml"
|
||||
INSTALL_MEDIAMTX=0
|
||||
MEDIAMTX_VERSION="1.15.3"
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
@@ -17,15 +15,13 @@ Options:
|
||||
-b, --binary <path> Path to the roverd binary (default: dist/roverd)
|
||||
-c, --config <path> Source config to install if /etc/roverd.yaml is missing
|
||||
(default: pi/roverd/roverd.sample.yaml)
|
||||
--mediamtx Install/download mediaMTX (binary, config, systemd unit)
|
||||
--mediamtx-version <v> Override mediaMTX release tag (default: 1.15.3)
|
||||
-h, --help Show this help text
|
||||
|
||||
The script must run from the repository root and as root (sudo). It will:
|
||||
* create system users/groups if needed
|
||||
* install /usr/local/bin/roverd and /etc/roverd.yaml
|
||||
* install /etc/systemd/system/roverd.service and enable the service
|
||||
* optionally install mediaMTX config/unit when --mediamtx is set
|
||||
* install /usr/local/bin/whip-publisher and its systemd unit
|
||||
* enable roverd.service and whip-publisher.service
|
||||
USAGE
|
||||
}
|
||||
|
||||
@@ -39,14 +35,6 @@ while [[ $# -gt 0 ]]; do
|
||||
CONFIG_SRC="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--mediamtx)
|
||||
INSTALL_MEDIAMTX=1
|
||||
shift
|
||||
;;
|
||||
--mediamtx-version)
|
||||
MEDIAMTX_VERSION="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
@@ -74,6 +62,13 @@ if [[ ! -f "$CONFIG_SRC" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v libcamera-vid >/dev/null 2>&1; then
|
||||
log "WARNING: libcamera-vid not found in PATH; install libcamera-utils for video publishing"
|
||||
fi
|
||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||
log "WARNING: ffmpeg not found in PATH; install ffmpeg for WHIP publishing"
|
||||
fi
|
||||
|
||||
ensure_user() {
|
||||
local user="$1"
|
||||
local groups="${2:-}"
|
||||
@@ -92,52 +87,7 @@ log() {
|
||||
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*"
|
||||
}
|
||||
|
||||
detect_mediamtx_asset() {
|
||||
local arch
|
||||
arch="$(uname -m)"
|
||||
case "$arch" in
|
||||
armv7l|armv6l)
|
||||
echo "mediamtx_v${MEDIAMTX_VERSION}_linux_armv7.tar.gz"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
echo "mediamtx_v${MEDIAMTX_VERSION}_linux_arm64.tar.gz"
|
||||
;;
|
||||
x86_64|amd64)
|
||||
echo "mediamtx_v${MEDIAMTX_VERSION}_linux_amd64.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo ""
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_mediamtx_binary() {
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "curl is required to download mediaMTX" >&2
|
||||
exit 1
|
||||
fi
|
||||
local asset
|
||||
asset="$(detect_mediamtx_asset)"
|
||||
if [[ -z "$asset" ]]; then
|
||||
echo "Unsupported architecture $(uname -m) for mediaMTX download" >&2
|
||||
exit 1
|
||||
fi
|
||||
local url="https://github.com/bluenviron/mediamtx/releases/download/v${MEDIAMTX_VERSION}/${asset}"
|
||||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
log "Downloading mediaMTX ${MEDIAMTX_VERSION} (${asset})"
|
||||
if ! curl -fsSL "$url" -o "${tmpdir}/${asset}"; then
|
||||
echo "Failed to download mediaMTX from ${url}" >&2
|
||||
rm -rf "$tmpdir"
|
||||
exit 1
|
||||
fi
|
||||
tar -xzf "${tmpdir}/${asset}" -C "$tmpdir" mediamtx
|
||||
install -o mediamtx -g mediamtx -m 0755 "${tmpdir}/mediamtx" /usr/local/bin/mediamtx
|
||||
log "Installed /usr/local/bin/mediamtx"
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
ensure_user roverd "dialout,gpio"
|
||||
ensure_user roverd "dialout,gpio,video"
|
||||
install -o roverd -g roverd -m 0755 "$BINARY_SRC" /usr/local/bin/roverd
|
||||
log "Installed roverd binary"
|
||||
|
||||
@@ -154,36 +104,32 @@ fi
|
||||
install -m 0644 pi/systemd/roverd.service /etc/systemd/system/roverd.service
|
||||
log "Installed roverd systemd unit"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable roverd.service
|
||||
if [[ $CONFIG_EXISTS -eq 1 ]]; then
|
||||
systemctl restart roverd.service
|
||||
log "Restarted roverd.service"
|
||||
else
|
||||
log "Skipped auto-start because config is the sample; edit $CONFIG_DEST then run: sudo systemctl restart roverd"
|
||||
# Install WHIP publisher assets
|
||||
install -D -o root -g root -m 0755 pi/bin/whip-publisher.sh /usr/local/bin/whip-publisher
|
||||
install -m 0644 pi/systemd/whip-publisher.service /etc/systemd/system/whip-publisher.service
|
||||
install -d -o roverd -g roverd /var/lib/roverd
|
||||
if [[ ! -f /var/lib/roverd/whip.env ]]; then
|
||||
cat > /var/lib/roverd/whip.env <<'ENV'
|
||||
# Managed by roverd; placeholder values will be overwritten at runtime.
|
||||
WHIP_URL=http://192.168.0.86:8889/whip/CHANGE_ME
|
||||
VIDEO_WIDTH=1280
|
||||
VIDEO_HEIGHT=720
|
||||
VIDEO_FPS=30
|
||||
VIDEO_BITRATE=3000000
|
||||
ENV
|
||||
chown roverd:roverd /var/lib/roverd/whip.env
|
||||
chmod 0640 /var/lib/roverd/whip.env
|
||||
fi
|
||||
|
||||
if [[ $INSTALL_MEDIAMTX -eq 1 ]]; then
|
||||
if [[ ! -f "pi/mediamtx/mediamtx.yml" ]]; then
|
||||
echo "pi/mediamtx/mediamtx.yml missing, cannot install mediaMTX config" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "pi/systemd/mediamtx.service" ]]; then
|
||||
echo "pi/systemd/mediamtx.service missing, cannot install mediaMTX unit" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ensure_user mediamtx "video"
|
||||
install_mediamtx_binary
|
||||
install -d -o mediamtx -g mediamtx /etc/mediamtx
|
||||
install -o mediamtx -g mediamtx -m 0644 pi/mediamtx/mediamtx.yml /etc/mediamtx/mediamtx.yml
|
||||
install -m 0644 pi/systemd/mediamtx.service /etc/systemd/system/mediamtx.service
|
||||
log "Installed mediamtx config and unit"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable mediamtx.service
|
||||
systemctl restart mediamtx.service
|
||||
log "Restarted mediamtx.service"
|
||||
systemctl daemon-reload
|
||||
systemctl enable roverd.service
|
||||
systemctl enable whip-publisher.service
|
||||
if [[ $CONFIG_EXISTS -eq 1 ]]; then
|
||||
systemctl restart roverd.service
|
||||
systemctl restart whip-publisher.service
|
||||
log "Restarted roverd + WHIP publisher"
|
||||
else
|
||||
log "Skipped auto-start because config is the sample; edit $CONFIG_DEST then run: sudo systemctl restart roverd whip-publisher"
|
||||
fi
|
||||
|
||||
log "Install complete"
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
logLevel: info
|
||||
api: yes
|
||||
apiAddress: 127.0.0.1:9997
|
||||
apiEncryption: no
|
||||
webrtc: yes
|
||||
webrtcLocalUDPAddress: :8189
|
||||
webrtcLocalTCPAddress: :8189
|
||||
webrtcAdditionalHosts: [ "localhost" ]
|
||||
|
||||
paths:
|
||||
rovercam:
|
||||
source: rpiCamera
|
||||
rpiCameraWidth: 1280
|
||||
rpiCameraHeight: 720
|
||||
rpiCameraFPS: 30
|
||||
rpiCameraBitrate: 1500000
|
||||
rpiCameraIDRPeriod: 30
|
||||
rpiCameraExposure: long
|
||||
rpiCameraHFlip: false
|
||||
rpiCameraVFlip: false
|
||||
@@ -21,6 +21,9 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("load config: %v", err)
|
||||
}
|
||||
if err := roverd.UpdatePublisherEnv(cfg.Media); err != nil {
|
||||
log.Fatalf("prepare media env: %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||
defer cancel()
|
||||
|
||||
+45
-61
@@ -3,9 +3,8 @@ package roverd
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
@@ -55,14 +54,16 @@ type BatteryConfig struct {
|
||||
}
|
||||
|
||||
type MediaConfig struct {
|
||||
WhepURL string `yaml:"whepUrl" json:"whepUrl,omitempty"`
|
||||
WhepPort int `yaml:"whepPort" json:"-"`
|
||||
WhepPath string `yaml:"whepPath" json:"-"`
|
||||
LegacyPublish string `yaml:"publishUrl,omitempty" json:"-"`
|
||||
PublishURL string `yaml:"publishUrl" json:"publishUrl,omitempty"`
|
||||
PublishPort int `yaml:"publishPort" json:"-"`
|
||||
Manage bool `yaml:"manage"`
|
||||
Service string `yaml:"service"`
|
||||
HealthURL string `yaml:"healthUrl"`
|
||||
HealthInterval Duration `yaml:"healthInterval"`
|
||||
VideoWidth int `yaml:"videoWidth" json:"-"`
|
||||
VideoHeight int `yaml:"videoHeight" json:"-"`
|
||||
VideoFPS int `yaml:"videoFps" json:"-"`
|
||||
VideoBitrate int `yaml:"videoBitrate" json:"-"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -93,9 +94,12 @@ func LoadConfig(path string) (*Config, error) {
|
||||
},
|
||||
},
|
||||
Media: MediaConfig{
|
||||
WhepPort: 8889,
|
||||
WhepPath: "/rovercam/whep",
|
||||
PublishPort: 8889,
|
||||
HealthInterval: Duration{Duration: 30 * time.Second},
|
||||
VideoWidth: 1280,
|
||||
VideoHeight: 720,
|
||||
VideoFPS: 30,
|
||||
VideoBitrate: 3000000,
|
||||
},
|
||||
}
|
||||
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
||||
@@ -125,69 +129,49 @@ func LoadConfig(path string) (*Config, error) {
|
||||
if cfg.Media.Manage && cfg.Media.HealthInterval.Duration <= 0 {
|
||||
cfg.Media.HealthInterval = Duration{Duration: 30 * time.Second}
|
||||
}
|
||||
if cfg.Media.WhepURL == "" {
|
||||
cfg.Media.WhepURL = cfg.Media.LegacyPublish
|
||||
if cfg.Media.VideoWidth <= 0 {
|
||||
cfg.Media.VideoWidth = 1280
|
||||
}
|
||||
if cfg.Media.WhepURL == "" {
|
||||
ip, err := detectPrimaryIPv4()
|
||||
if cfg.Media.VideoHeight <= 0 {
|
||||
cfg.Media.VideoHeight = 720
|
||||
}
|
||||
if cfg.Media.VideoFPS <= 0 {
|
||||
cfg.Media.VideoFPS = 30
|
||||
}
|
||||
if cfg.Media.VideoBitrate <= 0 {
|
||||
cfg.Media.VideoBitrate = 3000000
|
||||
}
|
||||
if cfg.Media.PublishPort <= 0 {
|
||||
cfg.Media.PublishPort = 8889
|
||||
}
|
||||
if cfg.Media.PublishURL == "" {
|
||||
derived, err := derivePublishURL(cfg.ServerURL, cfg.Name, cfg.Media.PublishPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("derive whepUrl: %w", err)
|
||||
return nil, fmt.Errorf("derive publishUrl: %w", err)
|
||||
}
|
||||
path := cfg.Media.WhepPath
|
||||
if path == "" {
|
||||
path = "/rovercam/whep"
|
||||
}
|
||||
path = ensureLeadingSlash(path)
|
||||
scheme := "http"
|
||||
cfg.Media.WhepURL = fmt.Sprintf("%s://%s:%d%s", scheme, ip, effectivePort(cfg.Media.WhepPort), path)
|
||||
cfg.Media.PublishURL = derived
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func ensureLeadingSlash(path string) string {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return "/" + path
|
||||
func derivePublishURL(serverURL, roverName string, port int) (string, error) {
|
||||
if roverName == "" {
|
||||
return "", errors.New("missing rover name for publishUrl")
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func effectivePort(port int) int {
|
||||
if port <= 0 {
|
||||
return 8889
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func detectPrimaryIPv4() (string, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
parsed, err := url.Parse(serverURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
|
||||
continue
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
return ip.String(), nil
|
||||
}
|
||||
host := parsed.Hostname()
|
||||
if host == "" {
|
||||
return "", errors.New("serverUrl missing host")
|
||||
}
|
||||
return "", errors.New("no non-loopback IPv4 address found")
|
||||
scheme := "http"
|
||||
if parsed.Scheme == "wss" || parsed.Scheme == "https" {
|
||||
scheme = "https"
|
||||
}
|
||||
if port <= 0 {
|
||||
port = 8889
|
||||
}
|
||||
return fmt.Sprintf("%s://%s:%d/whip/%s", scheme, host, port, url.PathEscape(roverName)), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package roverd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const publisherEnvPath = "/var/lib/roverd/whip.env"
|
||||
|
||||
func UpdatePublisherEnv(cfg MediaConfig) error {
|
||||
if cfg.PublishURL == "" {
|
||||
return fmt.Errorf("media publishUrl missing")
|
||||
}
|
||||
if cfg.VideoWidth <= 0 || cfg.VideoHeight <= 0 || cfg.VideoFPS <= 0 || cfg.VideoBitrate <= 0 {
|
||||
return fmt.Errorf("invalid media dimensions/bitrate")
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(publisherEnvPath), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, "WHIP_URL=%s\n", cfg.PublishURL)
|
||||
fmt.Fprintf(&buf, "VIDEO_WIDTH=%d\n", cfg.VideoWidth)
|
||||
fmt.Fprintf(&buf, "VIDEO_HEIGHT=%d\n", cfg.VideoHeight)
|
||||
fmt.Fprintf(&buf, "VIDEO_FPS=%d\n", cfg.VideoFPS)
|
||||
fmt.Fprintf(&buf, "VIDEO_BITRATE=%d\n", cfg.VideoBitrate)
|
||||
if err := os.WriteFile(publisherEnvPath, buf.Bytes(), 0o640); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -19,26 +19,36 @@ type MediaSupervisor struct {
|
||||
}
|
||||
|
||||
func NewMediaSupervisor(cfg MediaConfig, logger *log.Logger) *MediaSupervisor {
|
||||
if err := UpdatePublisherEnv(cfg); err != nil {
|
||||
logger.Printf("media supervisor: update env failed: %v", err)
|
||||
}
|
||||
if !cfg.Manage || cfg.Service == "" {
|
||||
return nil
|
||||
}
|
||||
if cfg.HealthURL == "" {
|
||||
cfg.HealthURL = "http://127.0.0.1:9997/v3/paths/list"
|
||||
}
|
||||
interval := cfg.HealthInterval.Duration
|
||||
if interval <= 0 {
|
||||
interval = 30 * time.Second
|
||||
}
|
||||
var client *http.Client
|
||||
if cfg.HealthURL != "" {
|
||||
client = &http.Client{Timeout: 5 * time.Second}
|
||||
}
|
||||
return &MediaSupervisor{
|
||||
cfg: cfg,
|
||||
logger: logger,
|
||||
client: &http.Client{Timeout: 5 * time.Second},
|
||||
client: client,
|
||||
checkInterval: interval,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MediaSupervisor) Start(ctx context.Context) {
|
||||
if m == nil || m.cfg.HealthURL == "" {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
if err := UpdatePublisherEnv(m.cfg); err != nil {
|
||||
m.logger.Printf("media supervisor: update env failed: %v", err)
|
||||
}
|
||||
if m.cfg.HealthURL == "" || m.client == nil {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
@@ -66,6 +76,9 @@ func (m *MediaSupervisor) HandleAction(ctx context.Context, action string) error
|
||||
if m == nil {
|
||||
return errors.New("media supervisor disabled")
|
||||
}
|
||||
if err := UpdatePublisherEnv(m.cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
switch action {
|
||||
case "start", "stop", "restart", "reload", "status":
|
||||
return m.runSystemctl(ctx, action)
|
||||
@@ -89,6 +102,9 @@ func (m *MediaSupervisor) checkAndRepair() error {
|
||||
}
|
||||
|
||||
func (m *MediaSupervisor) checkHealth(ctx context.Context) bool {
|
||||
if m.client == nil || m.cfg.HealthURL == "" {
|
||||
return true
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, m.cfg.HealthURL, nil)
|
||||
if err != nil {
|
||||
m.logger.Printf("media supervisor: health request: %v", err)
|
||||
|
||||
@@ -15,7 +15,13 @@ battery:
|
||||
urgent: 1650
|
||||
maxWheelSpeed: 350
|
||||
media:
|
||||
manage: false
|
||||
service: mediamtx.service
|
||||
healthUrl: http://127.0.0.1:9997/v3/paths/list
|
||||
publishUrl: http://192.168.0.86:8889/whip/roomba-alpha
|
||||
publishPort: 8889
|
||||
videoWidth: 1280
|
||||
videoHeight: 720
|
||||
videoFps: 30
|
||||
videoBitrate: 3000000
|
||||
manage: true
|
||||
service: whip-publisher.service
|
||||
healthUrl: ""
|
||||
healthInterval: 30s
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
[Unit]
|
||||
Description=mediaMTX WebRTC publisher
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/mediamtx /etc/mediamtx/mediamtx.yml
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=mediamtx
|
||||
Group=mediamtx
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Rover WHIP Publisher
|
||||
After=network-online.target roverd.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=roverd
|
||||
Group=roverd
|
||||
WorkingDirectory=/var/lib/roverd
|
||||
EnvironmentFile=/var/lib/roverd/whip.env
|
||||
ExecStart=/usr/local/bin/whip-publisher
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user