Datarhei - Dragon Fork: fork of datarhei/core with native WebRTC (WHEP) egress for low-latency streaming. Built with Pion.
Find a file
ZGaetano a2e0a8c083
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
feat(webrtc): add H.264 keyframe burst cache (issue #17)
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
.forgejo/workflows feat(ci): add Docker image publish workflow on tag push (closes #12) 2026-05-06 16:00:32 -04:00
.github Add linux/arm/v8 build 2026-03-16 09:28:04 +01:00
app feat(whip): wire WHIPHandler into API — struct field, MergedHooks, NewWHIPHandler, serverConfig, cleanup 2026-05-09 16:46:49 -04:00
cmd/webrtc-poc feat(webrtc): add -rtp-host flag + TrueNAS Docker deploy 2026-04-17 09:05:37 -04:00
config fix(config): preserve WebRTC section in Config.Clone() 2026-04-17 15:26:11 -04:00
core/webrtc feat(webrtc): add H.264 keyframe burst cache (issue #17) 2026-05-09 19:03:33 -04:00
deploy seed-data.sh: always refresh static/ and index.html from image 2026-05-09 17:21:05 -04:00
docs docs: add upstream rebase policy (closes #13) 2026-05-06 15:55:00 -04:00
encoding/json Add v16.7.2 2022-05-13 19:26:45 +02:00
ffmpeg Add looping_runtime to avstream status 2023-05-05 12:03:48 +02:00
glob Fix memfs concurrent read and write performance 2024-03-15 15:25:25 +01:00
http Add ProcessConfigWHIPIngest to API layer with Marshal/Unmarshal wiring 2026-05-09 17:01:49 -04:00
internal Update dependencies 2024-01-12 12:35:07 +01:00
io Fix memfs concurrent read and write performance 2024-03-15 15:25:25 +01:00
log Add WithLevel() to Logger interface 2024-05-29 15:51:51 +02:00
math/rand Fix concurrent accesses 2024-03-15 11:45:50 +01:00
monitor Fix typo in test name 2024-03-14 12:03:38 +01:00
net Fix tests 2023-04-26 09:50:09 +02:00
playout Add v16.7.2 2022-05-13 19:26:45 +02:00
process Fix race condition 2024-01-15 10:42:08 +01:00
prometheus test(prometheus): add WebRTC snapshot collector unit tests 2026-05-06 15:56:43 -04:00
psutil Fix #10 2023-04-11 15:04:31 +02:00
restream feat(restream): extend ProcessHooks with OnInputStart for WHIP ingest input legs 2026-05-09 16:32:03 -04:00
rtmp Don't report EOF as error in RTMP server, update dependency 2024-05-29 16:33:32 +02:00
service Add logging for service 2022-12-27 09:47:59 +01:00
session Fix require positive persist interval 2024-01-12 15:37:51 +01:00
src/misc/Logo Update rsLogo component to import from local images directory 2026-05-03 23:26:20 -04:00
srt Add support for SRTv4 clients 2024-01-12 15:38:32 +01:00
test chore: create test/load/results/ directory for load test reports 2026-05-06 16:04:13 -04:00
update Don't use deprecated functions from io/ioutil 2022-08-18 10:27:33 +03:00
vendor feat(webrtc): add ICE config helper (Configuration + SettingEngine) 2026-04-17 08:46:27 -04:00
.dockerignore Add v16.8.0 2022-06-03 17:21:52 +02:00
.editorconfig Add v16.7.2 2022-05-13 19:26:45 +02:00
.gitignore Merge branch 'm4-latency-gate' into m2-webrtc-core-integration 2026-05-03 12:26:21 +00:00
build.sh Add v16.7.2 2022-05-13 19:26:45 +02:00
CHANGELOG.md docs: update CHANGELOG for v0.2 backlog work (closes #11, #12, #13, #14) 2026-05-06 16:03:09 -04:00
CREDITS feat(branding): Dragon Fork identity for v0.1.0-dragonfork release 2026-05-03 12:22:25 +00:00
Dockerfile Add ubuntu build for vod branch 2024-09-24 11:47:25 +02:00
Dockerfile.bundle Mod exposes ports 2022-09-29 10:10:05 +02:00
Dockerfile.test Mod updates build-files 2023-02-23 10:17:39 +01:00
go.mod feat(webrtc): add ICE config helper (Configuration + SettingEngine) 2026-04-17 08:46:27 -04:00
go.sum feat(webrtc): add ICE config helper (Configuration + SettingEngine) 2026-04-17 08:46:27 -04:00
LICENSE Add v16.8.0 2022-06-03 17:21:52 +02:00
main.go Use config locations for import and ffmigrage 2023-01-03 11:45:10 +01:00
Makefile Bump version to 16.15.0, update changelog 2024-04-03 14:27:58 +02:00
mime.types Add v16.7.2 2022-05-13 19:26:45 +02:00
NOTES.md docs: add Dragon Fork WebRTC egress design spec and M1 plan 2026-04-17 08:40:05 -04:00
NOTICE feat(branding): Dragon Fork identity for v0.1.0-dragonfork release 2026-05-03 12:22:25 +00:00
README.md docs: update README quick-start with Prometheus/Grafana and Docker publish 2026-05-06 16:04:02 -04:00
run.sh Add test if import and migrate script exist 2024-04-04 11:10:10 +02:00
SECURITY.md Create SECURITY.md 2022-06-01 22:48:21 +02:00

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
            │                            │   (15 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 alongside rtmp.* and srt.*, with the same CORE_* env-var binding pattern.
  • Per-process webrtc.enabled toggle 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.enabled toggling.
  • 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: 406 on codec mismatch, 504 on ICE timeout, 503 on cap, 204 on 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 NOTICE for 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.