diff --git a/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.css b/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.css index 7ca4b4879..0b26402e0 100644 --- a/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.css +++ b/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.css @@ -127,6 +127,14 @@ mat-chip-row { margin-bottom: 7px; } +.agent-dispatch-options { + margin-bottom: 7px; +} + +#agent-restart-policy-select { + margin-left: 6px; +} + #ingress-url-type-select { margin-left: 6px; } diff --git a/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.html b/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.html index 4e1ac72c7..8bc04af8c 100644 --- a/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.html +++ b/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.html @@ -256,6 +256,68 @@ +
+ + + Room + + + + Agent name + + + + Dispatch ID + + +
+ +
+ + + + + + + + + + + + + + + +
+ + +
+ + Metadata + + + + Restart policy + + @for (policy of AGENT_RESTART_POLICIES; track policy) { + + {{policy.viewValue}} + + } + + +
+ + + diff --git a/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.ts index 19ec56416..2372becee 100644 --- a/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.ts +++ b/openvidu-testapp/src/app/components/dialogs/room-api-dialog/room-api-dialog.component.ts @@ -13,7 +13,7 @@ import { MatSelectModule } from '@angular/material/select'; import { MatIconModule } from '@angular/material/icon'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { VideoCodec } from '@livekit/protocol'; +import { JobRestartPolicy, VideoCodec } from '@livekit/protocol'; import { LocalParticipant } from 'livekit-client'; import { @@ -84,6 +84,17 @@ export class RoomApiDialogComponent { ingressUrlType: string = 'HTTP'; ingressUrlUri: string; + agentRoomName: string; + agentName: string = 'speech-processing'; + agentDispatchId: string; + agentMetadata: string; + agentRestartPolicySelected: JobRestartPolicy = JobRestartPolicy.JRP_ON_FAILURE; + + AGENT_RESTART_POLICIES: { value: JobRestartPolicy; viewValue: string }[] = [ + { value: JobRestartPolicy.JRP_ON_FAILURE, viewValue: 'On failure' }, + { value: JobRestartPolicy.JRP_NEVER, viewValue: 'Never' }, + ]; + response: string; INGRESS_INPUT_TYPES: { value: IngressInput; viewValue: string }[] = [ @@ -141,6 +152,7 @@ export class RoomApiDialogComponent { .values() .next().value?.trackSid!; this.ingressRoomName = this.room?.name; + this.agentRoomName = this.room?.name; } async listRooms() { @@ -365,6 +377,81 @@ export class RoomApiDialogComponent { } } + async createDispatch() { + console.log('Creating agent dispatch'); + try { + const dispatch = await this.roomApiService.createDispatch( + this.agentRoomName, + this.agentName, + this.agentMetadata || undefined, + this.agentRestartPolicySelected + ); + this.response = JSON.stringify(dispatch, null, 4); + this.agentDispatchId = dispatch.id; + } catch (error: any) { + this.response = error; + } + } + + async getDispatch() { + console.log('Getting agent dispatch'); + try { + const dispatch = await this.roomApiService.getDispatch( + this.agentDispatchId, + this.agentRoomName + ); + this.response = dispatch + ? JSON.stringify(dispatch, null, 4) + : 'Dispatch not found'; + } catch (error: any) { + this.response = error; + } + } + + async listDispatch() { + console.log('Listing agent dispatches'); + try { + const dispatches = await this.roomApiService.listDispatch( + this.agentRoomName + ); + this.response = JSON.stringify(dispatches, null, 4); + } catch (error: any) { + this.response = error; + } + } + + async deleteDispatch() { + console.log('Deleting agent dispatch'); + try { + await this.roomApiService.deleteDispatch( + this.agentDispatchId, + this.agentRoomName + ); + this.response = 'Agent dispatch deleted'; + } catch (error: any) { + this.response = error; + } + } + + async deleteAllDispatch() { + console.log('Deleting all agent dispatches'); + try { + const promises: Promise[] = []; + const dispatches = await this.roomApiService.listDispatch( + this.agentRoomName + ); + dispatches.forEach((d) => { + promises.push( + this.roomApiService.deleteDispatch(d.id, this.agentRoomName) + ); + }); + await Promise.all(promises); + this.response = 'Deleted ' + promises.length + ' agent dispatches'; + } catch (error: any) { + this.response = error; + } + } + addRtmpUrl(event: MatChipInputEvent): void { const value = (event.value || '').trim(); if (value) { diff --git a/openvidu-testapp/src/app/services/room-api.service.ts b/openvidu-testapp/src/app/services/room-api.service.ts index 8e28d4096..920354c16 100644 --- a/openvidu-testapp/src/app/services/room-api.service.ts +++ b/openvidu-testapp/src/app/services/room-api.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { AccessToken, + AgentDispatchClient, CreateIngressOptions, DirectFileOutput, EgressClient, @@ -25,7 +26,9 @@ import { import { LivekitParamsService } from './livekit-params.service'; import { VideoQuality } from 'livekit-client'; import { + AgentDispatch, IngressVideoEncodingOptions, + JobRestartPolicy, VideoCodec, VideoLayer, } from '@livekit/protocol'; @@ -46,6 +49,7 @@ export class RoomApiService { private roomServiceClient: RoomServiceClient; private egressClient: EgressClient; private ingressClient: IngressClient; + private agentDispatchClient: AgentDispatchClient; constructor( private http: HttpClient, @@ -66,6 +70,11 @@ export class RoomApiService { this.livekitParamsService.getParams().livekitApiKey, this.livekitParamsService.getParams().livekitApiSecret ); + this.agentDispatchClient = new AgentDispatchClient( + this.getRestUrl(), + this.livekitParamsService.getParams().livekitApiKey, + this.livekitParamsService.getParams().livekitApiSecret + ); } async createToken( @@ -328,6 +337,38 @@ export class RoomApiService { return await ingressClient.deleteIngress(ingressId); } + /* + * Agent Dispatch API + * https://docs.livekit.io/reference/agents/agent-dispatch-service-api/ + */ + + async createDispatch( + roomName: string, + agentName: string, + metadata?: string, + restartPolicy?: JobRestartPolicy + ): Promise { + return await this.agentDispatchClient.createDispatch(roomName, agentName, { + metadata, + restartPolicy, + }); + } + + async getDispatch( + dispatchId: string, + roomName: string + ): Promise { + return await this.agentDispatchClient.getDispatch(dispatchId, roomName); + } + + async listDispatch(roomName: string): Promise { + return await this.agentDispatchClient.listDispatch(roomName); + } + + async deleteDispatch(dispatchId: string, roomName: string): Promise { + return await this.agentDispatchClient.deleteDispatch(dispatchId, roomName); + } + private getRestUrl() { const wsUrl = this.livekitParamsService.getParams().livekitUrl; const protocol =