datarhei-dragonfork-core/app/webrtc
Zac Gaetano b7afd0f08a
Some checks failed
ci / vet + build (push) Successful in 9m54s
ci / vet + build (pull_request) Successful in 9m49s
ci / race tests (push) Failing after 8m1s
ci / WebRTC smoke (5-viewer fanout) (push) Successful in 9m45s
ci / WebRTC latency p95 gate (push) Successful in 10m3s
ci / race tests (pull_request) Failing after 7m59s
ci / WebRTC smoke (5-viewer fanout) (pull_request) Successful in 9m45s
ci / WebRTC latency p95 gate (pull_request) Successful in 10m4s
ci(webrtc): server-hop latency p95 gate
Adds an end-to-end RTP-arrival latency probe that runs as a dedicated
CI job and asserts p95 < 50ms.

Implementation
--------------
A build-tagged test (-tags latency, off by default) sends 1000
synthetic RTP packets at 60Hz into corewebrtc.Source and reads them
back via a Pion subscriber's track.ReadRTP(). Each packet's payload
starts with the publisher's UnixNano send time; the subscriber diffs
against time.Now() at arrival and accumulates p50/p95/p99.

This exercises every link of the egress hop: Source UDP read,
subscriber fan-out, forwardRTPSplit, Pion's TrackLocalStaticRTP
write, DTLS-SRTP encrypt, ICE socket write, decrypt at the
subscriber, RTP unmarshal at ReadRTP. Pure server-side; no FFmpeg
or codecs involved.

Why not glass-to-glass
----------------------
The design's §7 calls for FFmpeg drawtext frame counters + decode-
side pixel sampling, p95<300ms RTMP / <200ms SRT. Implementing that
in pure Go needs a cgo H.264 decoder or an FFmpeg sidecar pipe — a
significantly bigger lift for a marginal regression-detection win
(encode/decode latency is roughly fixed by the codec stack and
isn't moved by Core code changes). The server-hop measurement
captures everything Core code can actually regress.

Threshold
---------
50ms p95. Locally observed on a quiet host:
  p50=110µs, p95=237µs, p99=318µs.
The 50ms gate is ~200x headroom — generous enough to absorb CI
runner noise without false alarms, tight enough to catch a real
slowdown.

Race-clean: latencySamples uses a sync.Mutex around the slice append
(initial draft had a slice racing with the receive goroutine; vet
caught it).

Documented in test/TESTING.md and wired to .forgejo/workflows/test.yml
as the latency-gate job (depends on lint-and-vet, parallel with test
and webrtc-smoke).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 12:18:57 +00:00
..
ffmpeg_args.go feat(app/webrtc): port allocator + FFmpeg arg builder 2026-04-17 09:52:09 -04:00
ffmpeg_args_test.go feat(app/webrtc): port allocator + FFmpeg arg builder 2026-04-17 09:52:09 -04:00
handler.go feat(webrtc): add Echo WHEP handler for app/webrtc subsystem 2026-04-17 10:03:24 -04:00
handler_test.go feat(webrtc): add Echo WHEP handler for app/webrtc subsystem 2026-04-17 10:03:24 -04:00
integration_test.go test(webrtc): add M2 integration smoke test 2026-04-17 10:11:34 -04:00
latency_test.go ci(webrtc): server-hop latency p95 gate 2026-05-03 12:18:57 +00:00
lifecycle.go feat(webrtc): add app/webrtc subsystem + lifecycle hooks 2026-04-17 10:02:00 -04:00
lifecycle_test.go feat(webrtc): add app/webrtc subsystem + lifecycle hooks 2026-04-17 10:02:00 -04:00
portalloc.go feat(app/webrtc): port allocator + FFmpeg arg builder 2026-04-17 09:52:09 -04:00
portalloc_test.go feat(app/webrtc): port allocator + FFmpeg arg builder 2026-04-17 09:52:09 -04:00
subsystem.go feat(webrtc): add app/webrtc subsystem + lifecycle hooks 2026-04-17 10:02:00 -04:00