PHP code example of maatrics / livekit-server-sdk-php
1. Go to this page and download the library: Download maatrics/livekit-server-sdk-php library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
maatrics / livekit-server-sdk-php example snippets
use LiveKit\LiveKitAPI;
use LiveKit\Options\CreateRoomOptions;
$livekit = new LiveKitAPI('https://my-project.livekit.cloud', 'API_KEY', 'API_SECRET');
$room = $livekit->room->createRoom(new CreateRoomOptions(name: 'my-room', emptyTimeout: 300));
foreach ($livekit->room->listRooms() as $existing) {
echo $existing->getName(), PHP_EOL;
}
// One request, and the response the server built. The same call the Go, Python
// and Ruby SDKs give you, cursor and all.
$page = $livekit->egress->listEgress();
$items = $page->getItems();
$cursor = $page->getNextPageToken()?->getToken();
// One page at a time. The next is fetched only when you reach for it, so
// leaving the loop early leaves the remaining requests unmade.
foreach ($livekit->egress->iterateEgress() as $egress) {
break;
}
// Every page, collected into one array.
$all = $livekit->egress->listAllEgress();
use LiveKit\LiveKitAPI;
use LiveKit\Options\ClientOptions;
// Key and secret — the usual choice for a backend. The host needs its scheme:
// http(s), or ws(s), which is rewritten since the HTTP API shares the origin.
new LiveKitAPI('https://my-project.livekit.cloud', 'API_KEY', 'API_SECRET');
// A pre-signed token, for somewhere the API secret must not go. Its grants have
// to cover the calls you make with it.
new LiveKitAPI(
host: 'https://my-project.livekit.cloud',
options: new ClientOptions(token: $token),
);
// Nothing passed: read from LIVEKIT_URL plus either LIVEKIT_TOKEN, or
// LIVEKIT_API_KEY and LIVEKIT_API_SECRET.
new LiveKitAPI();
use LiveKit\AccessToken;
use LiveKit\Options\AccessTokenOptions;
use LiveKit\Grants\VideoGrant;
$token = new AccessToken('API_KEY', 'API_SECRET', new AccessTokenOptions(
identity: 'alice',
name: 'Alice',
ttl: '6h',
));
$token->addGrant(new VideoGrant(roomJoin: true, room: 'my-room'));
echo $token->toJwt();
use GuzzleHttp\Client;
$livekit = new LiveKit\LiveKitAPI(
host: 'https://my-project.livekit.cloud',
apiKey: 'API_KEY',
apiSecret: 'API_SECRET',
httpClient: new Client(['timeout' => 40]),
);
use LiveKit\Options\UpdateParticipantOptions;
foreach ($livekit->room->listParticipants('my-room') as $participant) {
echo $participant->getIdentity(), PHP_EOL;
}
$alice = $livekit->room->getParticipant('my-room', 'alice');
// Partial: only the fields you pass are changed. Everything omitted is left as
// it is rather than cleared, so you do not have to read-modify-write.
$livekit->room->updateParticipant('my-room', 'alice', new UpdateParticipantOptions(
name: 'Alice (host)',
metadata: '{"role":"host"}',
));
use LiveKit\Options\SendDataOptions;
use LiveKit\Proto\DataPacket\Kind;
$livekit->room->sendData(
'my-room',
json_encode(['type' => 'announcement', 'body' => 'starting now'], JSON_THROW_ON_ERROR),
Kind::RELIABLE,
new SendDataOptions(destinationIdentities: ['alice'], topic: 'chat'),
);
use LiveKit\Options\SendDataOptions;
use LiveKit\Proto\DataPacket\Kind;
$payload = 'starting now';
$options = new SendDataOptions(topic: 'chat', nonce: random_bytes(16));
// If this times out, retry it with the same $options rather than new ones.
$livekit->room->sendData('my-room', $payload, Kind::RELIABLE, $options);
use LiveKit\Options\EncodedOutputs;
use LiveKit\Options\RoomCompositeOptions;
use LiveKit\Proto\EncodedFileOutput;
use LiveKit\Proto\S3Upload;
$egress = $livekit->egress->startRoomCompositeEgress(
'my-room',
new EncodedOutputs(file: new EncodedFileOutput()
->setFilepath('my-room-{time}.mp4')
->setS3(new S3Upload()->setBucket('recordings')->setRegion('eu-central-1'))),
new RoomCompositeOptions(layout: 'speaker'),
);
foreach ($livekit->egress->listEgress() as $running) {
echo $running->getEgressId(), ' ', $running->getStatus(), PHP_EOL;
}
$livekit->egress->stopEgress($egress->getEgressId());
use LiveKit\Options\CreateIngressOptions;
use LiveKit\Options\ListIngressOptions;
use LiveKit\Options\UpdateIngressOptions;
use LiveKit\Proto\IngressInput;
$ingress = $livekit->ingress->createIngress(new CreateIngressOptions(
inputType: IngressInput::RTMP_INPUT,
name: 'studio feed',
roomName: 'my-room',
participantIdentity: 'rtmp-source',
));
echo $ingress->getUrl(), ' ', $ingress->getStreamKey(), PHP_EOL;
// Only the fields you pass are changed. Everything omitted keeps its current
// value rather than being cleared, which is why the options are all nullable.
$livekit->ingress->updateIngress($ingress->getIngressId(), new UpdateIngressOptions(
participantName: 'Studio',
));
$livekit->ingress->listIngress(new ListIngressOptions(roomName: 'my-room'));
$livekit->ingress->deleteIngress($ingress->getIngressId());
use LiveKit\Options\CreateDispatchOptions;
$dispatch = $livekit->agentDispatch->createDispatch(
'my-room',
'my-agent',
// Reaches the agent as job metadata: which customer, which language, which prompt.
new CreateDispatchOptions(metadata: '{"locale":"tr"}'),
);
$livekit->agentDispatch->listDispatch('my-room');
$one = $livekit->agentDispatch->getDispatch(dispatchId: $dispatch->getId(), room: 'my-room');
$livekit->agentDispatch->deleteDispatch(dispatchId: $dispatch->getId(), room: 'my-room');
use LiveKit\Options\CreateSipInboundTrunkOptions;
use LiveKit\Options\CreateSipOutboundTrunkOptions;
$inbound = $livekit->sip->createSipInboundTrunk(
'support line',
['+15551234567'],
new CreateSipInboundTrunkOptions(allowedAddresses: ['203.0.113.0/24']),
);
$outbound = $livekit->sip->createSipOutboundTrunk(
'provider',
'sip.provider.example',
['+15551234567'],
new CreateSipOutboundTrunkOptions(authUsername: 'user', authPassword: 'secret'),
);
use LiveKit\Options\CreateSipDispatchRuleOptions;
use LiveKit\Proto\SIPDispatchRule;
use LiveKit\Proto\SIPDispatchRuleIndividual;
// Every caller gets their own room, named from the prefix. SIPDispatchRuleDirect
// sends all callers to one named room instead; SIPDispatchRuleCallee keys the
// room on the number that was dialled.
$rule = new SIPDispatchRule()->setDispatchRuleIndividual(
new SIPDispatchRuleIndividual()->setRoomPrefix('call-')
);
$livekit->sip->createSipDispatchRule($rule, new CreateSipDispatchRuleOptions(
name: 'support',
trunkIds: [$inbound->getSipTrunkId()],
));
use LiveKit\Options\CreateSipParticipantOptions;
$participant = $livekit->sip->createSipParticipant(
$outbound->getSipTrunkId(),
'+15559876543',
'support-call',
new CreateSipParticipantOptions(participantIdentity: 'caller', waitUntilAnswered: true),
);
$livekit->sip->transferSipParticipant('support-call', 'caller', 'tel:+15551112222');
use LiveKit\Options\DialWhatsAppCallOptions;
$call = $livekit->connector->dialWhatsAppCall(
whatsappPhoneNumberId: 'PHONE_NUMBER_ID',
whatsappToPhoneNumber: '+15551234567',
whatsappApiKey: 'META_API_KEY',
whatsappCloudApiVersion: '23.0',
options: new DialWhatsAppCallOptions(roomName: 'support-call', ringingTimeout: 45),
);
echo $call->getWhatsappCallId(), ' in ', $call->getRoomName(), PHP_EOL;
use LiveKit\Options\ConnectWhatsAppCallOptions;
use LiveKit\Proto\SessionDescription;
$livekit->connector->connectWhatsAppCall(
$callIdFromTheDial,
new SessionDescription()->setType('answer')->setSdp($sdpFromTheWebhook),
new ConnectWhatsAppCallOptions(waitUntilAnswered: true, timeout: 45),
);
$livekit->connector->disconnectWhatsAppCall($callIdFromTheDial, 'META_API_KEY');
$livekit = new LiveKit\LiveKitAPI(
host: 'https://my-project.livekit.cloud',
apiKey: 'API_KEY',
apiSecret: 'API_SECRET',
options: new LiveKit\Options\ClientOptions(failover: false), // opt out
);
use LiveKit\Exceptions\SipCallError;
use LiveKit\Exceptions\TwirpErrorCode;
use LiveKit\Exceptions\TwirpException;
try {
$livekit->room->deleteRoom('my-room');
} catch (TwirpException $e) {
if ($e->getTwirpCode() === TwirpErrorCode::NOT_FOUND) {
// ...
}
echo $e->getHttpStatus(); // e.g. 404
print_r($e->getMeta());
}
try {
$livekit->room->deleteRoom('my-room');
} catch (TwirpException $e) {
if (($e->getMeta()[TwirpErrorCode::META_FROM_INTERMEDIARY] ?? null) === 'true') {
// Something between you and LiveKit answered: the original status is in
// meta['status_code'], and the body it sent in meta['body'].
}
}
try {
$livekit->sip->createSipParticipant(/* ... */);
} catch (SipCallError $e) {
echo $e->getSipStatusCode(); // e.g. 486
echo $e->getSipStatus(); // e.g. "Busy Here"
} catch (TwirpException $e) {
// any other Twirp failure
}
use LiveKit\Exceptions\TokenVerificationException;
try {
$claims = new LiveKit\TokenVerifier()->verify($jwt);
} catch (TokenVerificationException $e) {
if ($e->getPrevious() instanceof Firebase\JWT\ExpiredException) {
// ask for a fresh token
}
}
use LiveKit\AccessToken;
use LiveKit\Options\AccessTokenOptions;
use LiveKit\Proto\RoomConfiguration;
$token = new AccessToken('API_KEY', 'API_SECRET', new AccessTokenOptions(
identity: 'alice',
roomConfig: new RoomConfiguration()->setEmptyTimeout(300),
));
foreach ($room->getEnabledCodecs() as $codec) {
echo $codec->getMime(), PHP_EOL; // $codec is a Codec, not mixed
}
$room->setName(123); // Parameter #1 $var of method Room::setName() expects string
$room->setEmptyTimeout('x'); // ...expects int
use LiveKit\Contracts\RoomServiceClientInterface;
final readonly class RoomProvisioner
{
public function __construct(private RoomServiceClientInterface $rooms)
{
}
public function provision(string $name): string
{
return $this->rooms->createRoom(new CreateRoomOptions(name: $name))->getSid();
}
}
// Container wiring: one LiveKitAPI, its clients bound to their interfaces.
$livekit = new LiveKit\LiveKitAPI();
$container->set(RoomServiceClientInterface::class, $livekit->room);
$container->set(SipClientInterface::class, $livekit->sip);
$rooms = $this->createStub(RoomServiceClientInterface::class);
$rooms->method('createRoom')->willReturn(new Room()->setSid('RM_test'));
self::assertSame('RM_test', new RoomProvisioner($rooms)->provision('my-room'));
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.