[![Blax Software OSS](https://raw.githubusercontent.com/blax-software/laravel-workkit/master/art/oss-initiative-banner.svg)](https://github.com/blax-software) # Laravel WebRTC [![PHP Version](https://img.shields.io/badge/php-%5E8.1-blue?style=flat-square)](https://php.net) [![Laravel](https://img.shields.io/badge/laravel-10.x--12.x-orange?style=flat-square)](https://laravel.com) [![Built on](https://img.shields.io/badge/on-reactphp--kernel-4b275f?style=flat-square)](https://github.com/blax-software/reactphp-kernel) [![Tests](https://img.shields.io/badge/tests-17%20passing-success?style=flat-square)](#testing) [![Assertions](https://img.shields.io/badge/assertions-42-blue?style=flat-square)](#testing) [![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)](LICENSE) WebRTC for Laravel on the shared [`reactphp-kernel`](https://github.com/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. ## Features - 🎙️ **Record / intercept / log** — the engine terminates media server-side, so every participant's audio (human or AI) can be captured - 🤖 **AI realtime, provider hidden** — bridge a caller to an external realtime model (e.g. OpenAI Realtime) over a server-side socket; the browser only ever talks to *you*, and the model is a config swap - 👥 **Party-to-party & group calls** — `join`/`leave` a room and the `RoomManager` meshes each new peer with everyone already there (instructor↔student, controller↔pilot, guest↔admin) - 🧩 **On the shared kernel** — signaling runs on `reactphp-kernel` alongside your WebSockets, one process, one loop - 🔌 **Pluggable `MediaEngine`** — `NullMediaEngine` for signaling-only dev; `Str0mMediaEngine` for the real Rust-backed media - 🦀 **Rust media core** — `str0m` (sans-IO WebRTC) via `ext-php-rs`, shipped in `rust/` - 🎛️ **Transport-agnostic signaling** — route browser frames from this package's raw server or from `laravel-websockets` into the same handler ## Installation ```bash composer require blax-software/laravel-webrtc php artisan vendor:publish --tag="webrtc-config" ``` It depends on [`blax-software/reactphp-kernel`](https://github.com/blax-software/reactphp-kernel), resolved from git.blax.at via the `repositories` entry in `composer.json`. ## Quick Start Run the signaling server (on the shared kernel): ```bash php artisan webrtc:serve ``` With the default `NullMediaEngine`, signaling runs and the engine refuses `offer()` loudly. Build the Rust core (see [`rust/README.md`](rust/README.md)) and switch the engine for real calls: ```dotenv WEBRTC_MEDIA_ENGINE="Blax\WebRtc\Media\Str0mMediaEngine" ``` ### Signaling wire shape (newline-delimited JSON) ```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" } // low-level: mesh two peers { "type": "join", "peer": "p1", "room": "lobby" } // -> { "type": "joined", "peers": [...] } (auto-meshes) { "type": "leave", "peer": "p1" } // -> { "type": "left", "peers": [...] } { "type": "bridge", "peer": "p1", "options": {...} } // dial an external realtime model { "type": "close", "peer": "p1" } // closes media + leaves the room ``` `SignalingHandler` is transport-agnostic — feed it frames from the built-in raw `SignalingServer` today, or from the `laravel-websockets` WS transport (for browsers) later, without changing the media wiring. ## Configuration `config/webrtc.php` covers the signaling bind (`host`/`port`/`tls`), the `media_engine` binding, `recording` disk/path, advertised `ice_servers`, and the external `bridge` (e.g. OpenAI model + key). Swapping the realtime model — or the whole provider — is a server-side config change the browser never sees. ## Status **MVP scaffold.** Signaling + the engine abstraction are real, tested, and runnable with `NullMediaEngine`; the `Str0mMediaEngine` + `rust/` core are the seam to build next. This is the WebRTC half of the blax realtime stack. ## Architecture ``` 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/) ``` ## Testing ```bash composer install composer test ``` The signaling router and engines are unit-tested against a fake media engine — no browser, sockets, or external services required. ## License MIT. See [LICENSE](LICENSE). ## Star History Star History Chart