126 lines
5.3 KiB
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,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|