# blax-software/laravel-webrtc WebRTC for Laravel, built on the shared [`blax-software/reactphp-kernel`](https://git.blax.at/blax-software/reactphp-kernel) backbone. PHP owns **signaling + orchestration**; a pluggable **media engine** owns the real-time media (ICE/DTLS/SRTP/RTP/Opus) — with the production engine backed by a **Rust core (`str0m`) via `ext-php-rs`**, so PHP never runs per-20ms DSP. ``` reactphp-kernel shared backbone (loop, IPC, signals) └─ laravel-webrtc (this) signaling on the kernel ├─ NullMediaEngine signaling-only (dev/tests) └─ Str0mMediaEngine Rust/str0m core via ext-php-rs (rust/) ``` ## What it's for One media path that terminates server-side unlocks all of: - **Record / intercept / log** every participant's audio (human or AI). - **AI realtime, provider hidden** — the engine bridges a caller to an external realtime model (e.g. OpenAI Realtime) over a server-side socket; the browser only ever talks to *us*, and the model is a server-side config swap. - **Party-to-party & group calls** — instructor↔student, controller↔pilot, guest↔admin: participants are just peers the engine routes between. ## Status **Scaffold.** Signaling + the engine abstraction are real and runnable with `NullMediaEngine`; the `Str0mMediaEngine` + `rust/` core are the seam to build next (see `rust/README.md`). This package is the home for the WebRTC half of the blax realtime stack (rel learn-atc #1051/#1019). ## Install ```bash composer require blax-software/laravel-webrtc:dev-master php artisan vendor:publish --tag=webrtc-config ``` It depends on `blax-software/reactphp-kernel` (resolved from git.blax.at via the `repositories` entry in `composer.json`). ## Run ```bash php artisan webrtc:serve # signaling on config(webrtc.host:port) ``` With `NullMediaEngine` (default) signaling runs and the media engine refuses `offer()` loudly. Build the Rust core and set `WEBRTC_MEDIA_ENGINE=BlaxSoftware\LaravelWebRtc\Media\Str0mMediaEngine` for real calls. ## Signaling wire shape (JSON, newline-delimited) ```jsonc { "type": "offer", "peer": "p1", "sdp": "..." } // -> { "type": "answer", "peer": "p1", "sdp": "..." } { "type": "ice", "peer": "p1", "candidate": {...} } // (no reply) { "type": "record", "peer": "p1", "path": "..." } // -> { "type": "ack", ... } { "type": "connect", "peer": "p1", "other": "p2" } // party-to-party { "type": "bridge", "peer": "p1", "options": {...} } // dial an external realtime model { "type": "close", "peer": "p1" } ``` `SignalingHandler` is transport-agnostic — feed it frames from this package's raw `SignalingServer` today, or from the `laravel-websockets` WS transport (for browsers) later, without changing the media wiring. ## License MIT © Blax Software