Files
ladill-meet/app/Services/Meet/Media/LiveKitProvider.php
T
isaaccladandCursor 64df3d1eb1
Deploy Ladill Meet / deploy (push) Successful in 51s
Fix auto-record egress failing before LiveKit room exists.
Create rooms via the LiveKit API, retry egress when the room is missing, and resume server egress after the host connects when auto-record fell back to browser capture.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 09:53:44 +00:00

116 lines
3.4 KiB
PHP

<?php
namespace App\Services\Meet\Media;
use Agence104\LiveKit\AccessToken;
use Agence104\LiveKit\AccessTokenOptions;
use Agence104\LiveKit\RoomCreateOptions;
use Agence104\LiveKit\RoomServiceClient;
use Agence104\LiveKit\VideoGrant;
use Illuminate\Support\Facades\Log;
class LiveKitProvider implements MediaProviderInterface
{
public function createRoom(string $roomName, array $options = []): void
{
if (! $this->isConfigured()) {
return;
}
try {
$client = new RoomServiceClient(
$this->apiHost(),
(string) config('meet.media.livekit.api_key'),
(string) config('meet.media.livekit.api_secret'),
);
$client->createRoom(new RoomCreateOptions([
'name' => $roomName,
'empty_timeout' => (int) ($options['empty_timeout'] ?? 300),
]));
} catch (\Throwable $e) {
Log::warning('LiveKit createRoom failed.', [
'room' => $roomName,
'error' => $e->getMessage(),
]);
}
}
public function deleteRoom(string $roomName): void
{
if (! $this->isConfigured() || $roomName === '') {
return;
}
try {
$client = new RoomServiceClient(
$this->apiHost(),
(string) config('meet.media.livekit.api_key'),
(string) config('meet.media.livekit.api_secret'),
);
$client->deleteRoom($roomName);
} catch (\Throwable $e) {
Log::warning('LiveKit deleteRoom failed.', [
'room' => $roomName,
'error' => $e->getMessage(),
]);
}
}
public function generateToken(
string $roomName,
string $identity,
string $displayName,
array $grants = [],
): string {
$apiKey = (string) config('meet.media.livekit.api_key');
$apiSecret = (string) config('meet.media.livekit.api_secret');
$tokenOptions = (new AccessTokenOptions())
->setIdentity($identity)
->setName($displayName)
->setTtl(3600);
$videoGrant = (new VideoGrant())
->setRoomJoin()
->setRoomName($roomName)
->setCanPublish($grants['can_publish'] ?? true)
->setCanSubscribe($grants['can_subscribe'] ?? true)
->setCanPublishData($grants['can_publish_data'] ?? true);
if ($grants['room_admin'] ?? false) {
$videoGrant->setRoomAdmin();
}
return (new AccessToken($apiKey, $apiSecret))
->init($tokenOptions)
->setGrant($videoGrant)
->toJwt();
}
public function isConfigured(): bool
{
return filled(config('meet.media.livekit.url'))
&& filled(config('meet.media.livekit.api_key'))
&& filled(config('meet.media.livekit.api_secret'));
}
public function serverUrl(): string
{
return (string) config('meet.media.livekit.url');
}
public function apiHost(): string
{
$override = (string) config('meet.media.livekit.api_url', '');
if ($override !== '') {
return rtrim($override, '/');
}
$url = (string) config('meet.media.livekit.url', '');
return (string) preg_replace('#^wss:#', 'https:', (string) preg_replace('#^ws:#', 'http:', $url));
}
}