mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
whipwhep
This commit is contained in:
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
set +H
|
||||
|
||||
ENV_FILE="${VIDEO_ENV_FILE:-/var/lib/roverd/video.env}"
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "Environment file ${ENV_FILE} missing; cannot start audio forward listener" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
|
||||
: "${AUDIO_FORWARD_URL:?AUDIO_FORWARD_URL not set in ${ENV_FILE}}"
|
||||
PLAYBACK_DEVICE="${AUDIO_PLAYBACK_DEVICE:-forward}"
|
||||
|
||||
if [[ -n "${FFMPEG_BIN:-}" ]]; then
|
||||
FFMPEG_BIN_PATH="$FFMPEG_BIN"
|
||||
elif command -v ffmpeg >/dev/null 2>&1; then
|
||||
FFMPEG_BIN_PATH="$(command -v ffmpeg)"
|
||||
else
|
||||
echo "ffmpeg not found; install it via apt install ffmpeg." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command -v aplay >/dev/null 2>&1; then
|
||||
APLAY_BIN_PATH="$(command -v aplay)"
|
||||
else
|
||||
echo "aplay not found; install it via apt install alsa-utils." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LAST_FFMPEG_STATUS="unknown"
|
||||
LAST_APLAY_STATUS="unknown"
|
||||
|
||||
run_pipeline() {
|
||||
set +e
|
||||
"${FFMPEG_BIN_PATH}" \
|
||||
-hide_banner \
|
||||
-loglevel warning \
|
||||
-fflags nobuffer \
|
||||
-flags low_delay \
|
||||
-analyzeduration 200k \
|
||||
-probesize 32k \
|
||||
-i "${AUDIO_FORWARD_URL}" \
|
||||
-vn \
|
||||
-ac 1 \
|
||||
-ar 16000 \
|
||||
-f s16le \
|
||||
pipe:1 \
|
||||
| "${APLAY_BIN_PATH}" \
|
||||
-q \
|
||||
-D "${PLAYBACK_DEVICE}" \
|
||||
-t raw \
|
||||
-f S16_LE \
|
||||
-r 16000 \
|
||||
-c 1
|
||||
local rc=$?
|
||||
local -a statuses=("${PIPESTATUS[@]}")
|
||||
LAST_FFMPEG_STATUS="${statuses[0]:-unknown}"
|
||||
LAST_APLAY_STATUS="${statuses[1]:-unknown}"
|
||||
set -e
|
||||
return "${rc}"
|
||||
}
|
||||
|
||||
trap 'kill 0 2>/dev/null' EXIT INT TERM
|
||||
|
||||
while true; do
|
||||
if run_pipeline; then
|
||||
exit 0
|
||||
fi
|
||||
echo "Audio forward listener exited ffmpeg=${LAST_FFMPEG_STATUS:-unknown} aplay=${LAST_APLAY_STATUS:-unknown}, restarting in 2s..." >&2
|
||||
sleep 2
|
||||
done
|
||||
@@ -210,11 +210,16 @@ log "Installed video-publisher systemd unit"
|
||||
install -D -o root -g root -m 0755 pi/bin/audio-only-publisher.sh /usr/local/bin/audio-only-publisher
|
||||
install -m 0644 pi/systemd/audio-only-publisher.service /etc/systemd/system/audio-only-publisher.service
|
||||
log "Installed audio-only publisher helper + systemd unit"
|
||||
# Install audio-forward listener assets
|
||||
install -D -o root -g root -m 0755 pi/bin/audio-forward-listener.sh /usr/local/bin/audio-forward-listener
|
||||
install -m 0644 pi/systemd/audio-forward-listener.service /etc/systemd/system/audio-forward-listener.service
|
||||
log "Installed audio-forward listener helper + systemd unit"
|
||||
install -d -o roverd -g roverd /var/lib/roverd
|
||||
cat > /var/lib/roverd/video.env <<'ENV'
|
||||
# Managed by roverd; placeholder values will be overwritten at runtime.
|
||||
PUBLISH_URL=srt://192.168.0.86:9000?streamid=#!::r=CHANGE_ME,m=publish&latency=10&mode=caller&transtype=live&pkt_size=1316
|
||||
AUDIO_PUBLISH_URL=srt://192.168.0.86:9000?streamid=#!::r=CHANGE_ME-audio,m=publish&latency=10&mode=caller&transtype=live&pkt_size=1316
|
||||
AUDIO_FORWARD_URL=srt://192.168.0.86:9000?streamid=#!::r=CHANGE_ME-fwd,m=request&latency=10&mode=caller&transtype=live&pkt_size=1316
|
||||
VIDEO_BITRATE=2000000
|
||||
AUDIO_ENABLE=0
|
||||
AUDIO_DEVICE=hw:0,0
|
||||
@@ -245,13 +250,15 @@ systemctl daemon-reload
|
||||
systemctl enable roverd.service
|
||||
systemctl enable video-publisher.service
|
||||
systemctl enable audio-only-publisher.service
|
||||
systemctl enable audio-forward-listener.service
|
||||
if [[ $CONFIG_EXISTS -eq 1 ]]; then
|
||||
systemctl restart roverd.service
|
||||
systemctl restart video-publisher.service
|
||||
systemctl restart audio-only-publisher.service
|
||||
log "Restarted roverd + media publishers"
|
||||
systemctl restart audio-forward-listener.service
|
||||
log "Restarted roverd + media publishers/listener"
|
||||
else
|
||||
log "Skipped auto-start because config is the sample; edit $CONFIG_DEST then run: sudo systemctl restart roverd video-publisher audio-only-publisher"
|
||||
log "Skipped auto-start because config is the sample; edit $CONFIG_DEST then run: sudo systemctl restart roverd video-publisher audio-only-publisher audio-forward-listener"
|
||||
fi
|
||||
|
||||
log "Install complete"
|
||||
|
||||
@@ -80,6 +80,7 @@ type HornConfig struct {
|
||||
type MediaConfig struct {
|
||||
PublishURL string `yaml:"publishUrl" json:"publishUrl,omitempty"`
|
||||
AudioPublishURL string `yaml:"audioPublishUrl" json:"audioPublishUrl,omitempty"`
|
||||
AudioForwardURL string `yaml:"audioForwardUrl" json:"audioForwardUrl,omitempty"`
|
||||
PublishPort int `yaml:"publishPort" json:"-"`
|
||||
Manage bool `yaml:"manage"`
|
||||
ManageAudio bool `yaml:"manageAudio"`
|
||||
@@ -247,6 +248,13 @@ func LoadConfig(path string) (*Config, error) {
|
||||
}
|
||||
cfg.Media.AudioPublishURL = derived
|
||||
}
|
||||
if cfg.Media.AudioForwardURL == "" {
|
||||
derived, err := deriveReadURL(cfg.ServerURL, cfg.Name+"-fwd", cfg.Media.PublishPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("derive audioForwardUrl: %w", err)
|
||||
}
|
||||
cfg.Media.AudioForwardURL = derived
|
||||
}
|
||||
if err := validateServoConfig(&cfg.CameraServo); err != nil {
|
||||
return nil, fmt.Errorf("cameraServo: %w", err)
|
||||
}
|
||||
@@ -377,6 +385,10 @@ func derivePublishURL(serverURL, streamName string, port int) (string, error) {
|
||||
return deriveSRTURL(serverURL, streamName, port, "publish")
|
||||
}
|
||||
|
||||
func deriveReadURL(serverURL, streamName string, port int) (string, error) {
|
||||
return deriveSRTURL(serverURL, streamName, port, "request")
|
||||
}
|
||||
|
||||
func deriveSRTURL(serverURL, streamName string, port int, mode string) (string, error) {
|
||||
if streamName == "" {
|
||||
return "", errors.New("missing stream name for publishUrl")
|
||||
|
||||
@@ -27,6 +27,9 @@ func UpdatePublisherEnv(media MediaConfig, audio AudioConfig) error {
|
||||
if audio.CaptureEnabled && media.AudioPublishURL != "" {
|
||||
fmt.Fprintf(&buf, "AUDIO_PUBLISH_URL=%s\n", media.AudioPublishURL)
|
||||
}
|
||||
if media.AudioForwardURL != "" {
|
||||
fmt.Fprintf(&buf, "AUDIO_FORWARD_URL=%s\n", media.AudioForwardURL)
|
||||
}
|
||||
if media.VideoWidth > 0 {
|
||||
fmt.Fprintf(&buf, "VIDEO_WIDTH=%d\n", media.VideoWidth)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ battery:
|
||||
maxWheelSpeed: 350
|
||||
media:
|
||||
publishUrl: srt://192.168.0.86:9000?streamid=#!::r=roomba-alpha,m=publish&latency=10&mode=caller&transtype=live&pkt_size=1316
|
||||
audioForwardUrl: srt://192.168.0.86:9000?streamid=#!::r=roomba-alpha-fwd,m=request&latency=10&mode=caller&transtype=live&pkt_size=1316
|
||||
publishPort: 9000
|
||||
videoBitrate: 2000000
|
||||
manage: true
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[Unit]
|
||||
Description=Rover Audio Forward Listener (SRT -> ALSA)
|
||||
After=network-online.target roverd.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=roverd
|
||||
Group=roverd
|
||||
EnvironmentFile=/var/lib/roverd/video.env
|
||||
ExecStart=/usr/local/bin/audio-forward-listener
|
||||
KillMode=control-group
|
||||
TimeoutStopSec=5
|
||||
Restart=on-failure
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user