laravel-webrtc/src/WebRtcServiceProvider.php

126 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Blax\WebRtc;
use Blax\ReactPhpKernel\Kernel;
use Blax\WebRtc\Authorization\DefaultRoomAuthorizer;
use Blax\WebRtc\Console\Commands\InstallSfuBinary;
use Blax\WebRtc\Console\Commands\RunSfuSidecar;
use Blax\WebRtc\Console\Commands\StartWebRtcServer;
use Blax\WebRtc\Contracts\CallEventListener;
use Blax\WebRtc\Contracts\MediaEngine;
use Blax\WebRtc\Contracts\RecordingStore;
use Blax\WebRtc\Contracts\RoomAuthorizer;
use Blax\WebRtc\Contracts\RoomRegistry;
use Blax\WebRtc\Contracts\RoomStore;
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);
});
// 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,
]);
}
}
}
}