laravel-webrtc/README.md

5.2 KiB

Blax Software OSS

Laravel WebRTC

PHP Version Laravel Built on Tests Assertions License

WebRTC for Laravel on the shared 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 — instructor↔student, controller↔pilot, guest↔admin are just peers the engine routes between
  • 🧩 On the shared kernel — signaling runs on reactphp-kernel alongside your WebSockets, one process, one loop
  • 🔌 Pluggable MediaEngineNullMediaEngine for signaling-only dev; Str0mMediaEngine for the real Rust-backed media
  • 🦀 Rust media corestr0m (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

composer require blax-software/laravel-webrtc
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.

Quick Start

Run the signaling server (on the shared kernel):

php artisan webrtc:serve

With the default NullMediaEngine, signaling runs and the engine refuses offer() loudly. Build the Rust core (see rust/README.md) and switch the engine for real calls:

WEBRTC_MEDIA_ENGINE="Blax\WebRtc\Media\Str0mMediaEngine"

Signaling wire shape (newline-delimited JSON)

{ "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 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

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.

Star History

Star History Chart