# Datarhei — Dragon Fork

A fork of [datarhei/core](https://github.com/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:** M1–M4 complete, M5 (release) in flight. 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.
- **Browser-side smoke player** at `test/whep-player.html` —
  zero-dependency WHEP subscriber, ICE/codec/bitrate stats, JWT
  field, shareable `?url=&token=` URLs.
- **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)

```sh
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)
EOF

docker compose up -d --build
```

Then:

- Swagger UI: `http://<host>:8080/api/swagger/index.html`
- WHEP smoke player: open `test/whep-player.html` in a browser

### Sample process JSON

```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:

```json
"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`](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`](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`](docs/design/2026-04-17-datarhei-dragon-fork-m2-webrtc-core-integration.md) |
| Testing | [`test/TESTING.md`](test/TESTING.md) |
| Changelog (Dragon Fork) | [`CHANGELOG.md`](CHANGELOG.md) |
| Upstream Datarhei docs | [docs.datarhei.com/core](https://docs.datarhei.com/core) |

## Building from source

Go 1.24 required (vendored).

```sh
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
```

## 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`](NOTICE) for the required attribution.
- **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`](CREDITS).

## License

Apache License 2.0 — same as upstream. See [`LICENSE`](LICENSE).
