feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
# blax-webrtc-sfu — the Rust data plane
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
The sidecar binary behind `Blax\WebRtc\Media\RustMediaEngine`: **backend-hosted
|
|
|
|
|
rooms**. PHP/Laravel owns the control plane (rooms, auth, signaling
|
|
|
|
|
orchestration, billing hooks); this process owns everything per-packet.
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
- **ICE** (Interactive Connectivity Establishment — finds a working network
|
|
|
|
|
path to each browser), **DTLS** (the UDP TLS handshake that negotiates keys)
|
|
|
|
|
and **SRTP** (the encrypted media packets) are terminated here via
|
|
|
|
|
[str0m](https://github.com/algesten/str0m), a sans-IO Rust WebRTC stack.
|
|
|
|
|
- **SFU forwarding** (Selective Forwarding Unit): each peer's Opus audio is
|
|
|
|
|
received once and forwarded to the other peers of its room **without
|
|
|
|
|
decoding** — one loop thread, one shared UDP socket, `rtc.accepts()`
|
|
|
|
|
demultiplexing.
|
|
|
|
|
- **Recording**: per-peer Ogg/Opus written straight from the depayloaded
|
|
|
|
|
stream — playable by ffmpeg/browsers, no transcoding, no client cooperation.
|
|
|
|
|
- **Negotiation**: the initial offer/answer arrives via the control socket
|
|
|
|
|
(from PHP signaling). Renegotiation as peers join rides each browser's
|
|
|
|
|
WebRTC **data channel** directly — PHP never relays it (see str0m's `chat`
|
|
|
|
|
example, which this follows).
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
## Control protocol (PHP ⇄ sidecar)
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
JSON-lines over a Unix socket. Requests carry an `id` echoed by the reply;
|
|
|
|
|
notices are pushed without one.
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
```
|
|
|
|
|
→ {"id":1,"cmd":"add_peer","room":"lobby","peer":"alice","offer":"v=0…","record":"/rec/alice.ogg"}
|
|
|
|
|
← {"id":1,"ok":true,"answer":"v=0…"}
|
|
|
|
|
→ {"id":2,"cmd":"mute_peer","room":"lobby","peer":"alice","muted":true}
|
|
|
|
|
→ {"id":3,"cmd":"record_start","room":"lobby","peer":"alice","path":"/rec/a.ogg"} (record_stop too)
|
|
|
|
|
→ {"id":4,"cmd":"remove_peer","room":"lobby","peer":"alice"}
|
|
|
|
|
→ {"id":5,"cmd":"stats"} ← rooms → peers → {connected, muted, seconds}
|
|
|
|
|
→ {"id":6,"cmd":"ping"} / {"id":7,"cmd":"shutdown"}
|
|
|
|
|
← {"event":"peer_connected","room":"lobby","peer":"alice"}
|
|
|
|
|
← {"event":"peer_left","room":"lobby","peer":"alice","seconds":42.5}
|
|
|
|
|
```
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
## Build & test
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
```bash
|
|
|
|
|
cargo build && cargo test # 7 tests incl. an end-to-end control-socket run
|
|
|
|
|
./build-release.sh # static musl release + .sha256 into dist/
|
2026-07-07 11:07:59 +00:00
|
|
|
```
|
|
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
On NixOS: `nix-shell -p gcc pkg-config openssl perl gnumake musl --run ./build-release.sh`.
|
|
|
|
|
|
|
|
|
|
## Releasing
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
`BinaryManager::VERSION` (PHP) pins the release tag it downloads from. To ship:
|
|
|
|
|
build `dist/` artifacts (linux-x86_64 at minimum), attach both files to the
|
|
|
|
|
Forgejo release with that tag, and bump `VERSION` when the protocol changes.
|
|
|
|
|
PHP resolves binaries in this order: `webrtc.sfu.binary` override → a local
|
|
|
|
|
`target/{release,debug}` build (dev) → the downloaded install.
|
|
|
|
|
|
|
|
|
|
## CLI
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
blax-webrtc-sfu --socket /run/sfu.sock --udp-ip 0.0.0.0 --udp-port 41000 --public-ip 203.0.113.9
|
|
|
|
|
```
|
2026-07-07 11:07:59 +00:00
|
|
|
|
feat: Rust SFU data plane — backend-hosted rooms, plug-and-play sidecar binary
rust/ becomes a standalone static binary (blax-webrtc-sfu, tokio-free
std-thread loop on str0m): terminates ICE/DTLS/SRTP, forwards Opus between
room peers without decoding, records per-peer Ogg/Opus (ffprobe-verified),
server-side mute/kick, stats + peer_connected/peer_left usage events, all
driven by PHP over a JSON-lines Unix control socket. Renegotiation rides the
browser data channel (str0m chat model) — signaling only carries the initial
offer/answer.
PHP side: RustMediaEngine (MediaEngine contract + room-aware API) is
plug-and-play — first use downloads the sha256-verified prebuilt binary
(BinaryManager, RoadRunner pattern) and spawns it detached, flock-guarded
(SidecarSupervisor). webrtc:install / webrtc:sidecar provided for explicit
control; config gains the webrtc.sfu block. Replaces the ext-php-rs
Str0mMediaEngine seam.
Tests: 61 PHP (incl. a real PHP<->Rust E2E that spawns the sidecar from
PHPUnit) + 7 Rust (incl. an end-to-end control-socket integration test).
build-release.sh produces the static-musl release + .sha256 (verified:
static-pie, 9.2MB, runs).
Card #1083 (rel #1051 #1060 #1064).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:29:26 +00:00
|
|
|
`--udp-port 0` (default) picks an ephemeral port — fine on one host, pin it in
|
|
|
|
|
production and publish it (UDP) on the container. `--public-ip` is what
|
|
|
|
|
browsers are told to reach in the ICE host candidate; it defaults to the
|
|
|
|
|
default-route interface address.
|