WebRTC audio mirror: AAC cannot cross WebRTC, so transcode audio to Opus into <path>.webrtc

bin/mtx-on-ready.sh (runOnReady inside the mediamtx container) posts the is-live notice and, for sources whose
audio is not Opus, runs ffmpeg: video copy, audio -> Opus, published over MediaMTX's loopback RTSP to
<user>/<Title>.webrtc (record: no). dumpd accepts .webrtc publishes only from 127.0.0.1. The portal hides
mirror paths, plays the mirror over WHEP (HLS stays on the source), holds an AAC source for 15 s while its
mirror comes up, and corrects the viewer count. Verified headless with a mocked path list.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-11-01 13:58:15 -06:00
parent f060277167
commit 9bdf9f1947
8 changed files with 99 additions and 26 deletions

View File

@@ -372,7 +372,12 @@ def write_mediamtx(public_host=""):
Path("mediamtx.yml").write_text(f"""# MediaMTX — ingest only. No playback endpoints exposed. (generated by configure.py)
logLevel: info
rtsp: no
# RTSP only on the container loopback: the audio-mirror hook (bin/mtx-on-ready.sh) reads the source and publishes
# "<path>.webrtc" through it. Not published by compose, unreachable from outside.
rtsp: yes
rtspAddress: 127.0.0.1:8554
rtspTransports: [tcp]
rtspEncryption: "no"
moq: no
metrics: no
pprof: no
@@ -417,15 +422,16 @@ pathDefaults:
recordPartDuration: 1s
recordSegmentDuration: 12h # one file per stream unless it runs >12h
recordDeleteAfter: 0s # never auto-delete; the archive job handles it
# optional Discord "is live" notice (LIVE_WEBHOOK_URL set in .env). busybox wget in the -ffmpeg image.
runOnReady: >
sh -c '[ -n "$LIVE_WEBHOOK_URL" ] || exit 0;
u="${{MTX_PATH%%/*}}"; t="${{MTX_PATH#*/}}";
wget -q -O /dev/null --header="Content-Type: application/json"
--post-data="{{\\"content\\":\\"🔴 **$u** is live: $t — https://$LIVE_HOST/\\"}}" "$LIVE_WEBHOOK_URL"'
# on ready: optional Discord "is live" notice (LIVE_WEBHOOK_URL in .env) + the WebRTC audio mirror
# (bin/mtx-on-ready.sh, bind-mounted by compose; AAC cannot cross WebRTC, so audio is transcoded to Opus into <path>.webrtc)
runOnReady: /vanguard/on-ready.sh
runOnReadyRestart: no
paths:
# audio mirrors (first rule wins): never recorded, no hook; only publishable from inside the container (dumpd)
~^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+\\.webrtc$:
record: no
runOnReady: ""
# <username>/<Title>; dumpd decides who may publish where (token user == prefix)
~^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$: {{}}
""")