Go to file
Blax Software 1479e36f49 feat: multi-party rooms + real socket round-trip test
- Rooms\Room + Rooms\RoomManager: track peers per room, auto-mesh a new joiner
  with everyone already there, drop empty rooms
- SignalingHandler: join/leave message types (auto-connectPeers on join), and
  close now also leaves the room; expose rooms()
- SignalingServer::address() for the bound listen address
- Tests: real offer->answer round-trip over a live TCP socket on the kernel loop,
  RoomManager + join/leave/close coverage. Suite: 17 tests / 42 assertions
- Verified on the updated reactphp-kernel (logging + registry)

rel learn-atc #1055 #1051 #1019

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 13:54:36 +02:00
config feat: WebRTC MVP to Blax standard (namespace, README, tests, scaffolding) 2026-07-07 13:28:49 +02:00
rust feat: initial laravel-webrtc scaffold on the reactphp-kernel 2026-07-07 13:07:59 +02:00
src feat: multi-party rooms + real socket round-trip test 2026-07-07 13:54:36 +02:00
tests feat: multi-party rooms + real socket round-trip test 2026-07-07 13:54:36 +02:00
.gitattributes feat: WebRTC MVP to Blax standard (namespace, README, tests, scaffolding) 2026-07-07 13:28:49 +02:00
.gitignore feat: initial laravel-webrtc scaffold on the reactphp-kernel 2026-07-07 13:07:59 +02:00
CHANGELOG.md feat: multi-party rooms + real socket round-trip test 2026-07-07 13:54:36 +02:00
LICENSE feat: initial laravel-webrtc scaffold on the reactphp-kernel 2026-07-07 13:07:59 +02:00
README.md feat: multi-party rooms + real socket round-trip test 2026-07-07 13:54:36 +02:00
composer.json feat: WebRTC MVP to Blax standard (namespace, README, tests, scaffolding) 2026-07-07 13:28:49 +02:00
phpunit.xml.dist feat: WebRTC MVP to Blax standard (namespace, README, tests, scaffolding) 2026-07-07 13:28:49 +02:00
pint.json feat: WebRTC MVP to Blax standard (namespace, README, tests, scaffolding) 2026-07-07 13:28:49 +02:00
test.sh feat: WebRTC MVP to Blax standard (namespace, README, tests, scaffolding) 2026-07-07 13:28:49 +02:00

README.md

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 callsjoin/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 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" }       // 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

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