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. |
||
|---|---|---|
| .forgejo/workflows | ||
| .github | ||
| app | ||
| cmd/webrtc-poc | ||
| config | ||
| core/webrtc | ||
| deploy | ||
| docs | ||
| encoding/json | ||
| ffmpeg | ||
| glob | ||
| http | ||
| internal | ||
| io | ||
| log | ||
| math/rand | ||
| monitor | ||
| net | ||
| playout | ||
| process | ||
| prometheus | ||
| psutil | ||
| restream | ||
| rtmp | ||
| service | ||
| session | ||
| src/misc/Logo | ||
| srt | ||
| test | ||
| update | ||
| vendor | ||
| .dockerignore | ||
| .editorconfig | ||
| .gitignore | ||
| build.sh | ||
| CHANGELOG.md | ||
| CREDITS | ||
| Dockerfile | ||
| Dockerfile.bundle | ||
| Dockerfile.test | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| Makefile | ||
| mime.types | ||
| NOTES.md | ||
| NOTICE | ||
| README.md | ||
| run.sh | ||
| SECURITY.md | ||
Datarhei — Dragon Fork
A fork of datarhei/core that adds a native WebRTC (WHEP) egress path. Everything upstream Datarhei already does — RTMP / SRT / RTSP ingest, FFmpeg process orchestration, HLS / DASH outputs, S3 mounts, the HTTP API and Swagger UI — works unchanged. WebRTC sits alongside as another output type, opt-in per process.
publisher (OBS / FFmpeg / SRT) ──▶ datarhei Core ──▶ WebRTC peers
│ │ (1–5 viewers per stream)
│ ├──▶ HLS / DASH (existing)
│ ├──▶ RTMP relay (existing)
└──▶ ingest (RTMP / SRT / …) └──▶ recording (existing)
Sub-second glass-to-glass on a LAN over WHEP, no SFU dependencies, single binary, single Docker image.
Status: v0.2 in progress (last work 2026-05-06). Full GUI bundled (Restreamer UI + Wild Dragon WebRTC admin). Prometheus + Grafana observability stack shipped. Live deploy running on TrueNAS since 2026-04-17.
What this fork adds
webrtc.*config block alongsidertmp.*andsrt.*, with the sameCORE_*env-var binding pattern.- Per-process
webrtc.enabledtoggle on the existing process config. Once true, Core auto-injects two RTP output legs (video + audio), allocates UDP ports, and the WHEP endpoint is live. POST /api/v3/whep/{processID}— WebRTC-HTTP Egress Protocol subscribe; SDP offer in, SDP answer out. JWT-protected by the existing Core auth.DELETE /api/v3/whep/{processID}/{resourceID}— idempotent teardown.PATCH …/{resourceID}— trickle ICE.- Bundled GUI — the upstream Restreamer React UI is built into the
TrueNAS deploy image with Wild Dragon branding, plus a single-file
Wild Dragon WebRTC admin page for one-click
webrtc.enabledtoggling. - Browser-side smoke player at
whep-player.html— zero-dependency WHEP subscriber, ICE/codec/bitrate stats, JWT field, shareable?url=&token=URLs. - Prometheus observability — eleven
dragonfork_webrtc_*metrics (RED-method counters/histograms + state gauges). Grafana health dashboard with 5 rows and 4 pre-loaded alert rules. - Multi-viewer correctness: per-stream peer cap, ICE-failure auto-cleanup, process-stop broadcast tear-down.
- Error matrix per the design spec:
406on codec mismatch,504on ICE timeout,503on cap,204on idempotent DELETE, CORS preflights on every WHEP route.
The existing upstream Datarhei feature set is intact — see "From upstream Datarhei" below.
Quick start
Docker (TrueNAS / any host with Docker + LAN-reachable IP)
git clone https://forge.wilddragon.net/zgaetano/datarhei-dragonfork-core.git
cd datarhei-dragonfork-core/deploy/truenas/core
cat > .env <<EOF
PUBLIC_IP=10.0.0.25
CORE_HTTP_PORT=8080
API_AUTH_USERNAME=admin
API_AUTH_PASSWORD=$(openssl rand -base64 24)
API_AUTH_JWT_SECRET=$(openssl rand -base64 48)
GRAFANA_ADMIN_PASSWORD=$(openssl rand -base64 24)
GRAFANA_PORT=3000
PROM_PORT=9090
EOF
docker compose up -d --build
Then open in a browser (replace <host> with your PUBLIC_IP):
| URL | What it does |
|---|---|
http://<host>:8080/ |
Restreamer UI — manage processes, ingests, outputs |
http://<host>:8080/wilddragon-webrtc.html |
Wild Dragon WebRTC admin — toggle webrtc.enabled per process, copy WHEP URL |
http://<host>:8080/whep-player.html |
WHEP smoke player — verify the WebRTC stream renders |
http://<host>:3000/ |
Grafana — WebRTC Health dashboard (login with GRAFANA_ADMIN_PASSWORD) |
http://<host>:9090/ |
Prometheus — raw metrics, alert rules |
http://<host>:8080/api/swagger/index.html |
Swagger — full API docs |
The Restreamer UI doesn't yet have a WebRTC checkbox in its process
editor — use /wilddragon-webrtc.html for that. Tracked in issue #15.
Pulling a pre-built image (after first tag is published)
# Update .env, then:
docker compose pull # pulls pre-built multi-arch image
docker compose up -d # no --build needed
Sample process JSON
{
"id": "live",
"input": [
{ "address": "{rtmp,name=live.stream}", "options": [] }
],
"output": [],
"webrtc": { "enabled": true }
}
That's it. No webrtc:// URL scheme to learn — the toggle on
config.webrtc.enabled is the entire surface. The resolver allocates
ports, injects -f rtp udp://… legs into the FFmpeg command, and the
WHEP endpoint at /api/v3/whep/live becomes live the moment the
process starts.
For multi-input pipelines (lavfi test sources, multi-camera switches,
SDI + file audio), use the video_map and audio_map fields:
"webrtc": {
"enabled": true,
"video_map": "0:v:0",
"audio_map": "1:a:0",
"force_transcode": true
}
Documentation
| Topic | Where |
|---|---|
| Design spec | docs/design/2026-04-16-datarhei-dragon-fork-webrtc-design.md |
| M1 (PoC) plan | docs/design/2026-04-16-datarhei-dragon-fork-m1-webrtc-poc.md |
| M2 (Core integration) spec | docs/design/2026-04-17-datarhei-dragon-fork-m2-webrtc-core-integration.md |
| Prometheus metrics design | docs/design/2026-05-03-datarhei-dragon-fork-webrtc-prometheus-metrics-design.md |
| Upstream rebase policy | docs/REBASE.md |
| TrueNAS deploy guide | deploy/truenas/core/README.md |
| Testing | test/TESTING.md |
| Changelog (Dragon Fork) | CHANGELOG.md |
| Upstream Datarhei docs | docs.datarhei.com/core |
Building from source
Go 1.24 required (vendored).
make release # cross-compiles linux/amd64 to ./core/core
make test # full suite, race detector
go test -tags latency -timeout 90s -count=1 \
-run TestLatencyServerHop ./app/webrtc/... # latency p95 gate
Load testing
go run ./test/load/sustained.go \
-url http://<host>:8080 \
-stream <processID> \
-peers 5 \
-duration 10m \
-auth "Bearer <TOKEN>" \
-out test/load/results/
Reports are written to test/load/results/. Observe the Grafana
WebRTC Health dashboard during the run.
From upstream Datarhei
This fork preserves everything upstream Datarhei Core does — Dragon Fork is purely additive. If a feature isn't WebRTC-related, the behaviour is unchanged from upstream and the upstream documentation applies as-is.
| Subsystem | Upstream feature set |
|---|---|
| Process management | API-driven FFmpeg, error detection / recovery, log history, resource limits, statistics, FFprobe input verification, process metadata |
| Media delivery | HTTP/S, RTMP/S, SRT services with Let's Encrypt, configurable file systems (in-memory / disk / S3), HLS/DASH session limits, viewer session API |
| Misc | HTTP REST + GraphQL, Swagger, Prometheus metrics, multi-arch Docker images |
Attribution
Dragon Fork is built on:
- datarhei Core — Apache 2.0, © datarhei. The base repository this
fork tracks. See
NOTICEfor the required attribution. - datarhei Restreamer UI — Apache 2.0, © datarhei. The React frontend bundled into the TrueNAS deploy image with Wild Dragon overlays.
- Pion WebRTC — MIT. The Go WebRTC stack the egress path is built on.
- FFmpeg — LGPL / GPL (build-flag dependent). Used as a subprocess for transcoding and RTP packetisation; Dragon Fork doesn't link against it.
Full third-party credits in CREDITS.
License
Apache License 2.0 — same as upstream. See LICENSE.