laravel-webrtc/src/WebRtcServiceProvider.php

126 lines
5.3 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Blax\WebRtc;
use Blax\ReactPhpKernel\Kernel;
feat: full package — typed rooms (public/private/presence/open-presence) + call recording Rooms - Rooms\RoomType derived from the name prefix (like laravel-websockets channels): public, private-* (authorized), presence-* (authorized + member list), open-presence-* (public + member list). Room/RoomManager carry per-member info. - Contracts\RoomAuthorizer + secure DefaultRoomAuthorizer (denies private/presence until the host binds one). Presence rooms broadcast the member list + info. Recording (store the FULL call audio, in PHP, today) - Pure-P2P audio is DTLS-SRTP end-to-end, so the server can't capture it. Instead the browser MediaRecords its mic and streams chunks over the WS as BINARY frames (needs the new laravel-ws onBinary); RelaySignalingHandler appends them per participant via a RecordingStore. Recording\FileRecordingStore -> <room>/<peer>.webm. welcome/joined carry a record flag telling the client to stream. - Contracts\CallEventListener call-log seam (peer/room/recording lifecycle) so calls are auditable even when unrecorded. Wiring - RelaySignalingHandler(authorizer, recorder, events); webrtc:serve + provider + config/webrtc.php (recording enabled/path/format, authorizer, events). Tests 35/99 incl on-disk FileRecordingStore, presence member lists, auth gating, binary recording+finalize+events, RoomType, and the real WS round-trip. README documents room types + the browser MediaRecorder->WS recording flow. rel learn-atc #1060 #1055 #1057 #1051 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 07:01:12 +00:00
use Blax\WebRtc\Authorization\DefaultRoomAuthorizer;
use Blax\WebRtc\Console\Commands\InstallSfuBinary;
use Blax\WebRtc\Console\Commands\RunSfuSidecar;
use Blax\WebRtc\Console\Commands\StartWebRtcServer;
feat: full package — typed rooms (public/private/presence/open-presence) + call recording Rooms - Rooms\RoomType derived from the name prefix (like laravel-websockets channels): public, private-* (authorized), presence-* (authorized + member list), open-presence-* (public + member list). Room/RoomManager carry per-member info. - Contracts\RoomAuthorizer + secure DefaultRoomAuthorizer (denies private/presence until the host binds one). Presence rooms broadcast the member list + info. Recording (store the FULL call audio, in PHP, today) - Pure-P2P audio is DTLS-SRTP end-to-end, so the server can't capture it. Instead the browser MediaRecords its mic and streams chunks over the WS as BINARY frames (needs the new laravel-ws onBinary); RelaySignalingHandler appends them per participant via a RecordingStore. Recording\FileRecordingStore -> <room>/<peer>.webm. welcome/joined carry a record flag telling the client to stream. - Contracts\CallEventListener call-log seam (peer/room/recording lifecycle) so calls are auditable even when unrecorded. Wiring - RelaySignalingHandler(authorizer, recorder, events); webrtc:serve + provider + config/webrtc.php (recording enabled/path/format, authorizer, events). Tests 35/99 incl on-disk FileRecordingStore, presence member lists, auth gating, binary recording+finalize+events, RoomType, and the real WS round-trip. README documents room types + the browser MediaRecorder->WS recording flow. rel learn-atc #1060 #1055 #1057 #1051 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 07:01:12 +00:00
use Blax\WebRtc\Contracts\CallEventListener;
use Blax\WebRtc\Contracts\MediaEngine;
use Blax\WebRtc\Contracts\RecordingStore;
feat: full package — typed rooms (public/private/presence/open-presence) + call recording Rooms - Rooms\RoomType derived from the name prefix (like laravel-websockets channels): public, private-* (authorized), presence-* (authorized + member list), open-presence-* (public + member list). Room/RoomManager carry per-member info. - Contracts\RoomAuthorizer + secure DefaultRoomAuthorizer (denies private/presence until the host binds one). Presence rooms broadcast the member list + info. Recording (store the FULL call audio, in PHP, today) - Pure-P2P audio is DTLS-SRTP end-to-end, so the server can't capture it. Instead the browser MediaRecords its mic and streams chunks over the WS as BINARY frames (needs the new laravel-ws onBinary); RelaySignalingHandler appends them per participant via a RecordingStore. Recording\FileRecordingStore -> <room>/<peer>.webm. welcome/joined carry a record flag telling the client to stream. - Contracts\CallEventListener call-log seam (peer/room/recording lifecycle) so calls are auditable even when unrecorded. Wiring - RelaySignalingHandler(authorizer, recorder, events); webrtc:serve + provider + config/webrtc.php (recording enabled/path/format, authorizer, events). Tests 35/99 incl on-disk FileRecordingStore, presence member lists, auth gating, binary recording+finalize+events, RoomType, and the real WS round-trip. README documents room types + the browser MediaRecorder->WS recording flow. rel learn-atc #1060 #1055 #1057 #1051 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 07:01:12 +00:00
use Blax\WebRtc\Contracts\RoomAuthorizer;
use Blax\WebRtc\Contracts\RoomRegistry;
use Blax\WebRtc\Contracts\RoomStore;
feat: full package — typed rooms (public/private/presence/open-presence) + call recording Rooms - Rooms\RoomType derived from the name prefix (like laravel-websockets channels): public, private-* (authorized), presence-* (authorized + member list), open-presence-* (public + member list). Room/RoomManager carry per-member info. - Contracts\RoomAuthorizer + secure DefaultRoomAuthorizer (denies private/presence until the host binds one). Presence rooms broadcast the member list + info. Recording (store the FULL call audio, in PHP, today) - Pure-P2P audio is DTLS-SRTP end-to-end, so the server can't capture it. Instead the browser MediaRecords its mic and streams chunks over the WS as BINARY frames (needs the new laravel-ws onBinary); RelaySignalingHandler appends them per participant via a RecordingStore. Recording\FileRecordingStore -> <room>/<peer>.webm. welcome/joined carry a record flag telling the client to stream. - Contracts\CallEventListener call-log seam (peer/room/recording lifecycle) so calls are auditable even when unrecorded. Wiring - RelaySignalingHandler(authorizer, recorder, events); webrtc:serve + provider + config/webrtc.php (recording enabled/path/format, authorizer, events). Tests 35/99 incl on-disk FileRecordingStore, presence member lists, auth gating, binary recording+finalize+events, RoomType, and the real WS round-trip. README documents room types + the browser MediaRecorder->WS recording flow. rel learn-atc #1060 #1055 #1057 #1051 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 07:01:12 +00:00
use Blax\WebRtc\Events\NullCallEventListener;
use Blax\WebRtc\Media\NullMediaEngine;
use Blax\WebRtc\Media\Rust\BinaryManager;
use Blax\WebRtc\Media\Rust\SidecarSupervisor;
use Blax\WebRtc\Realtime\OpenAiRealtimeBridge;
use Blax\WebRtc\Recording\FileRecordingStore;
use Blax\WebRtc\Rooms\ConfigRoomRegistry;
use Blax\WebRtc\Rooms\RoomManager;
use Blax\WebRtc\Rooms\Stores\ArrayRoomStore;
use Blax\Ws\WebSocketServer;
use Illuminate\Support\ServiceProvider;
class WebRtcServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(__DIR__.'/../config/webrtc.php', 'webrtc');
// Resolve the configured media engine wherever a MediaEngine is type-hinted.
$this->app->bind(MediaEngine::class, function ($app) {
$class = (string) config('webrtc.media_engine', NullMediaEngine::class);
return $app->make($class);
});
feat: full package — typed rooms (public/private/presence/open-presence) + call recording Rooms - Rooms\RoomType derived from the name prefix (like laravel-websockets channels): public, private-* (authorized), presence-* (authorized + member list), open-presence-* (public + member list). Room/RoomManager carry per-member info. - Contracts\RoomAuthorizer + secure DefaultRoomAuthorizer (denies private/presence until the host binds one). Presence rooms broadcast the member list + info. Recording (store the FULL call audio, in PHP, today) - Pure-P2P audio is DTLS-SRTP end-to-end, so the server can't capture it. Instead the browser MediaRecords its mic and streams chunks over the WS as BINARY frames (needs the new laravel-ws onBinary); RelaySignalingHandler appends them per participant via a RecordingStore. Recording\FileRecordingStore -> <room>/<peer>.webm. welcome/joined carry a record flag telling the client to stream. - Contracts\CallEventListener call-log seam (peer/room/recording lifecycle) so calls are auditable even when unrecorded. Wiring - RelaySignalingHandler(authorizer, recorder, events); webrtc:serve + provider + config/webrtc.php (recording enabled/path/format, authorizer, events). Tests 35/99 incl on-disk FileRecordingStore, presence member lists, auth gating, binary recording+finalize+events, RoomType, and the real WS round-trip. README documents room types + the browser MediaRecorder->WS recording flow. rel learn-atc #1060 #1055 #1057 #1051 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 07:01:12 +00:00
// Room authorization (private/presence) + the call-event log — host-overridable.
$this->app->bind(RoomAuthorizer::class, function ($app) {
return $app->make((string) config('webrtc.authorizer', DefaultRoomAuthorizer::class));
});
$this->app->bind(CallEventListener::class, function ($app) {
return $app->make((string) config('webrtc.events', NullCallEventListener::class));
});
// Room membership store — swappable so a fork-per-message host (learn-atc's
// existing WS) can back it with Cache/Redis instead of process memory. The
// RoomManager is per-resolve so a fresh worker reads current state.
$this->app->bind(RoomStore::class, function ($app) {
return $app->make((string) config('webrtc.room_store', ArrayRoomStore::class));
});
$this->app->bind(RoomManager::class, function ($app) {
return new RoomManager($app->make(RoomStore::class));
});
// The backend-defined room registry: which rooms exist and each room's
// transport (p2p vs server-handled). Defaults to the config-driven registry;
// a host binds its own (e.g. a DB/Eloquent-backed registry so rooms are
// created + edited at runtime) via `webrtc.room_registry`.
$this->app->bind(RoomRegistry::class, function ($app) {
$class = config('webrtc.room_registry');
return $class
? $app->make($class)
: new ConfigRoomRegistry((array) config('webrtc.rooms', []));
});
// Where a call's audio is stored (per participant). Host may override the class.
$this->app->bind(RecordingStore::class, function () {
$recording = (array) config('webrtc.recording', []);
return new FileRecordingStore(
(string) ($recording['path'] ?? 'webrtc'),
(string) ($recording['format'] ?? 'webm'),
);
});
// The Rust SFU sidecar (backend-hosted rooms): binary management + the
// process supervisor RustMediaEngine boots plug-and-play on first use.
$this->app->singleton(BinaryManager::class, function () {
return new BinaryManager((array) config('webrtc.sfu', []));
});
$this->app->singleton(SidecarSupervisor::class, function ($app) {
return new SidecarSupervisor($app->make(BinaryManager::class), (array) config('webrtc.sfu', []));
});
// Realtime AI bridge (provider hidden from the browser, model swappable server-side).
$this->app->bind(OpenAiRealtimeBridge::class, function () {
$endpoint = (string) config('webrtc.bridge.openai.endpoint', 'wss://api.openai.com/v1/realtime');
return new OpenAiRealtimeBridge(endpoint: $endpoint);
});
}
public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__.'/../config/webrtc.php' => $this->app->configPath('webrtc.php'),
], 'webrtc-config');
// The Rust SFU sidecar commands have no extra PHP dependencies.
$this->commands([
InstallSfuBinary::class,
RunSfuSidecar::class,
]);
// The bundled ReactPHP relay server needs blax-software/laravel-ws +
// reactphp-kernel (dev-only deps). A host that only consumes the domain
// layer (rooms/recording/realtime bridge) on its OWN transport won't have
// them — checking the dependency classes first avoids autoloading the
// command (and its imports) when they're absent.
if (class_exists(WebSocketServer::class) && class_exists(Kernel::class)) {
$this->commands([
StartWebRtcServer::class,
]);
}
}
}
}