Commit graph

438 commits

Author SHA1 Message Date
891f65dff6 docs: add v0.2 and v0.3 implementation notes
Some checks failed
ci / vet + build (push) Failing after 5m0s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
Documents the SDK gap and monkey-patch workaround, seed-data.sh
no-clobber problem, keyframe cache lock ordering rationale, and
the STAP-A IDR detection gap.
2026-05-10 13:07:04 -04:00
c4857f5581 docs: add v0.3.0-dragonfork CHANGELOG entry
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
Covers WHIP ingest backend, keyframe cache, Wild Dragon UI WHIP toggle,
seed-data.sh always-overwrite fix, and the full core/webrtc test suite.
2026-05-10 13:06:06 -04:00
228ed4b09b test(webrtc): Source Subscribe pre-fill, Close, and EnableKeyFrameCache
Some checks failed
ci / vet + build (push) Failing after 5m0s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
Covers:
- Subscribe pre-fills channel from IDR cache immediately on call
- No pre-fill when cache is not enabled
- Labeled-break stops pre-fill when bufDepth < burst length
- Close closes all subscriber channels (no goroutine leak)
- EnableKeyFrameCache is idempotent (second call is a no-op)
2026-05-10 09:23:40 -04:00
293536563f test(webrtc): unit tests for keyFrameCache and isH264IDRStart
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
Covers:
- isH264IDRStart: empty, single-NAL IDR (type 5), single-NAL non-IDR
  (SPS/PPS/P-frame), FU-A start IDR, FU-A start non-IDR, FU-A
  continuation, truncated FU-A, Opus payload
- push/snapshot: IDR reset, burst accumulation, double-IDR reset
- Capacity caps: maxPackets, maxBytes
- Snapshot independence: copy isolated from subsequent mutations
- Concurrent safety: 1 writer + 4 readers (-race clean)
2026-05-10 09:23:12 -04:00
7490edd770 feat(webrtc): enable keyframe cache on video sources (issue #17)
Some checks failed
ci / vet + build (push) Failing after 5m1s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
Call videoSrc.EnableKeyFrameCache() immediately after binding the video
UDP Source in allocAdjacentPair(). Audio sources are intentionally left
uncached — IDR detection on Opus packets would accumulate the entire
audio stream without ever resetting the burst.
2026-05-09 19:05:11 -04:00
020a1800ce feat(webrtc): wire keyframe cache into Source (issue #17)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
- Add cache *keyFrameCache field to Source (nil by default).
- Add EnableKeyFrameCache() — call before Start() on video sources to
  activate IDR burst caching.
- readLoop: call cache.push(pkt) after each successful unmarshal, before
  the subscriber fanout. No lock held at push time — push acquires its
  own mutex internally.
- Subscribe: snapshot the cache outside s.mu to avoid any cross-lock
  complexity, then pre-fill the new channel with the burst before
  registering it in the subscriber set. Uses a labeled break to stop
  pre-filling if the channel is full (bufDepth too small for the burst;
  the subscriber will wait for the next live keyframe instead).
2026-05-09 19:04:17 -04:00
a2e0a8c083 feat(webrtc): add H.264 keyframe burst cache (issue #17)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
Introduces keyFrameCache — a bounded ring buffer that retains all RTP
packets from the most recent H.264 IDR NAL unit until the packet just
before the next one. New WHEP subscribers receive this burst immediately
on Subscribe(), cutting first-frame latency from up to one IDR interval
(typically ~2 s at GOP=60/30fps) to nearly zero.

Design notes:
- Detection covers single-NAL (type 5) and FU-A start (type 28, start
  bit set, inner type 5). STAP-A IDR leading is not handled — FFmpeg
  never uses STAP-A for IDR slices in practice.
- Bounded at 512 packets / 2 MiB per source to cap memory per stream.
- push() is called only from the single-goroutine readLoop; the lock
  it holds is tiny and brief.
- snapshot() returns a shallow copy; *rtp.Packet values are immutable
  after being placed in the cache so sharing is safe.
2026-05-09 19:03:33 -04:00
353fa0f3f3 seed-data.sh: always refresh static/ and index.html from image
Some checks failed
ci / vet + build (push) Failing after 5m7s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
The React bundle hash changes every time the UI is rebuilt. With the old
no-clobber approach, a redeployed container kept serving the old bundle
because the static/ directory already existed on the data volume.

Fix: always overwrite index.html, asset-manifest.json, and the entire
static/ subdirectory from /core/static on every container start. These
are build artifacts (not operator-edited content) so overwriting is safe.
All other top-level entries (channels/, config/, etc.) remain no-clobber.
2026-05-09 17:21:05 -04:00
4d94c88d74 Add ProcessConfigWHIPIngest to API layer with Marshal/Unmarshal wiring
Some checks failed
ci / vet + build (push) Failing after 5m1s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
Adds ProcessConfigWHIPIngest struct to http/api/process.go and wires it
into ProcessConfig.Marshal() and ProcessConfig.Unmarshal() so that the
WHIPIngest.Enabled flag can be set via API and correctly propagates to
app.Config.WHIPIngest, which is checked by onWHIPProcessStart in
app/webrtc/whip_lifecycle.go.

Without this change, app.Config.WHIPIngest.Enabled was always false and
WHIP ingest could never activate regardless of what the UI sent.
2026-05-09 17:01:49 -04:00
4ac63ddfc6 feat(whip): wire WHIPHandler into API — struct field, MergedHooks, NewWHIPHandler, serverConfig, cleanup
Some checks failed
ci / vet + build (push) Failing after 5m0s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
2026-05-09 16:46:49 -04:00
7f545962f6 fix(whip): wire teardown hook in NewWHIPHandler constructor (mirrors WHEP NewHandler pattern)
Some checks failed
ci / vet + build (push) Failing after 5m1s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
2026-05-09 16:38:29 -04:00
1be78a8185 feat(whip): wire WHIPHandler into HTTP server Config and v3 routes
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:35:48 -04:00
a22b8c68f0 fix(whip): clean up lifecycle — proper net import and checkPortFree implementation
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:34:20 -04:00
b1057756d2 fix(whip): rewrite lifecycle hooks — correct port allocation, clean FFmpeg RTP input legs
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:33:35 -04:00
4bef6563c7 feat(whip): extend Subsystem with WHIP ingest state, lookupIngest, WHIPHooks
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:32:49 -04:00
6c9d1864dd feat(restream): extend ProcessHooks with OnInputStart for WHIP ingest input legs
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:32:03 -04:00
ca3501f888 feat(whip): add WHIP process lifecycle hooks — port allocation and FFmpeg RTP input legs
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:27:25 -04:00
d72aa8afe1 feat(whip): add WHIPHandler — Echo HTTP handler for WHIP ingest endpoints
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:26:42 -04:00
2a4c8d5f52 fix(docker): chmod apply-overlay.sh before execution (exit 126)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-09 16:25:28 -04:00
01c456cd1a feat(core/webrtc): add IngestPeer for WHIP publish side (issue #16)
Some checks failed
ci / vet + build (push) Failing after 5m3s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
IngestPeer is the symmetric inverse of the WHEP Peer:
- Creates a recvonly PeerConnection (Pion receives tracks from the publisher)
- OnTrack -> reads RTP packets from the remote track and writes them to
  loopback UDP ports (videoPort, audioPort) that FFmpeg is listening on
- Full lifecycle: Done(), Connected(), Close(), AddICECandidate()

PeerFactory.CreateIngestPeer() follows the same ctx/offer/ICE-gather
pattern as CreatePeerFromSources() so the app/webrtc handler layer can
use a uniform error matrix.
2026-05-09 16:20:09 -04:00
5f9ba6f764 feat(config): add ConfigWHIPIngest to per-process config (issue #16)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
Adds the ConfigWHIPIngest struct alongside the existing ConfigWebRTC.
When Enabled=true the app/webrtc subsystem (next commit) will prepend
RTP UDP input legs to the FFmpeg command, binding on loopback ports
that WHIP publisher peers write received WebRTC tracks to.
2026-05-09 16:18:43 -04:00
890b09a33c fix(build): remove promauto dependency, use explicit reg.MustRegister
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
promauto is not in the vendor tree. Replace promauto.With(reg).NewXxx()
with prometheus.NewXxx() + reg.MustRegister() — functionally identical
but uses only the already-vendored prometheus/client_golang/prometheus
package. Fixes the vendor-mode build error:

  cannot find module providing package .../prometheus/promauto
2026-05-09 16:16:31 -04:00
70d0ddb2e3 gui: redesign WebRTC admin page with Wild Dragon brand
Some checks failed
ci / vet + build (push) Failing after 4m50s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
- Rajdhani + JetBrains Mono typefaces via Google Fonts
- Deep dark palette: #09090d bg, #ff5c28 accent
- 22px dot-grid background texture
- Sticky frosted-glass header with WD monogram SVG
- Wild Dragon wordmark SVG on login panel
- Process cards with border-left state indicator (green/amber/red)
- Animated pulse dots on state badges
- Cleaner WHEP URL row with Copy + Open buttons
- Log panels hidden until first entry (no empty box on load)
- All JS functionality preserved (JWT auth, toggle+restart, WHEP copy)
2026-05-09 12:27:08 -04:00
dd639b697f feat(ui): source UI build from wilddragon-restreamer-ui fork (issue #15)
Some checks failed
ci / vet + build (push) Failing after 4m49s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
2026-05-06 16:21:23 -04:00
917225c994 chore: create test/load/results/ directory for load test reports
Some checks failed
ci / vet + build (push) Failing after 4m50s
ci / race tests (push) Has been skipped
ci / WebRTC smoke (5-viewer fanout) (push) Has been skipped
ci / WebRTC latency p95 gate (push) Has been skipped
2026-05-06 16:04:13 -04:00
9e9c7eb8f1 docs: update README quick-start with Prometheus/Grafana and Docker publish
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 16:04:02 -04:00
55b61dd0e5 docs: update CHANGELOG for v0.2 backlog work (closes #11, #12, #13, #14)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 16:03:09 -04:00
561a93e044 feat(test): add 5-peer sustained WHEP load test (closes #14)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 16:01:22 -04:00
60f64fe76b feat(ci): add Docker image publish workflow on tag push (closes #12)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 16:00:32 -04:00
28a280b9b3 feat(deploy): add Prometheus + Grafana observability stack (closes #11)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 16:00:15 -04:00
4beab3423d feat(deploy): add Grafana WebRTC health dashboard
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:59:56 -04:00
6b637a35e6 feat(deploy): add Grafana dashboard provisioning config
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:59:24 -04:00
7471507be7 feat(deploy): add Grafana Prometheus datasource provisioning
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:59:18 -04:00
e8f39daa75 feat(deploy): add WebRTC Prometheus alert rules
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:59:11 -04:00
4b8d9f0e8c feat(deploy): add Prometheus scrape config
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:59:00 -04:00
1748f9102d test(webrtc): add metrics unit tests
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:58:50 -04:00
47a28bf9d4 feat(webrtc): instrument WHEP handler with Prometheus metrics
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:58:26 -04:00
1d7cd5b520 feat(webrtc): add StreamCount() for metrics snapshot
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:57:13 -04:00
15af16ce97 test(prometheus): add WebRTC snapshot collector unit tests
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:56:43 -04:00
23636e4a76 feat(prometheus): add WebRTC snapshot collector
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:56:27 -04:00
eaf62b7397 feat(webrtc): add WebRTC Prometheus metrics (direct instrumentation)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:56:12 -04:00
70324aad28 feat(webrtc): add Connected() channel to Peer for ICE establishment timing
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:55:42 -04:00
2283a32f2a docs: add upstream rebase policy (closes #13)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-06 15:55:00 -04:00
99c568e53e Update rsLogo component to import from local images directory
Some checks failed
ci / vet + build (push) Successful in 9m49s
ci / race tests (push) Failing after 8m16s
ci / WebRTC smoke (5-viewer fanout) (push) Successful in 9m58s
ci / WebRTC latency p95 gate (push) Successful in 10m7s
2026-05-03 23:26:20 -04:00
6c3f887faa Update Logo component to import from local images directory
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-03 23:26:13 -04:00
6449f65468 feat(branding): replace placeholder logo192 with real Wild Dragon logo
Some checks failed
ci / vet + build (push) Successful in 9m51s
ci / race tests (push) Failing after 8m11s
ci / WebRTC smoke (5-viewer fanout) (push) Successful in 10m1s
ci / WebRTC latency p95 gate (push) Successful in 10m10s
2026-05-03 17:25:42 -04:00
9a618f0b70 docs(readme): mention the GUI surface in the quick-start
Some checks failed
ci / vet + build (push) Successful in 9m50s
ci / race tests (push) Failing after 8m8s
ci / WebRTC smoke (5-viewer fanout) (push) Successful in 9m54s
ci / WebRTC latency p95 gate (push) Successful in 10m4s
Users running v0.2 already have a full UI; calling it out so it isn't
just discovered by accident.
2026-05-03 16:34:44 -04:00
86a5a50dec docs(deploy): document the GUI surface (Restreamer UI + Wild Dragon WebRTC admin)
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
2026-05-03 16:33:48 -04:00
2d2bd0e5c6 docs(changelog): v0.2.0-dragonfork — GUI ship
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
Calls out the Restreamer UI bundle (which has been in the deploy
bundle since M2 but undocumented) and the new wilddragon-webrtc.html
admin page.
2026-05-03 16:32:56 -04:00
27cc39dab0 feat(deploy): add Wild Dragon WebRTC admin page
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled
Single-file HTML/JS admin page seeded into /core/data alongside
whep-player.html. Lets an operator log in with the API_AUTH_USERNAME
+ API_AUTH_PASSWORD creds, list every process, and toggle webrtc.enabled
per process with a single button. WHEP URL displayed for enabled
processes with a one-click "open in WHEP player" link.

Closes the v0.1 GUI gap: the upstream Restreamer UI we ship doesn't
know about Core's webrtc config block, so toggling WebRTC required
direct API calls. This page is the user-friendly path. Reachable at
/wilddragon-webrtc.html on any deploy.

No build step — drops in via the existing seed-data.sh flow.
2026-05-03 16:31:13 -04:00