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 =