mirror of https://github.com/OpenVidu/openvidu.git
openvidu-testapp: refactor room service to use Node SDKs
parent
e1634efe39
commit
d156db6051
|
@ -21,6 +21,7 @@
|
|||
"@angular/platform-browser": "^16.2.11",
|
||||
"@angular/platform-browser-dynamic": "^16.2.11",
|
||||
"@angular/router": "^16.2.11",
|
||||
"@livekit/protocol": "^1.27.1",
|
||||
"buffer": "^6.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
|
||||
<div class="button-group">
|
||||
<button mat-button id="list-rooms-api-btn" (click)="listRooms()">List Rooms</button>
|
||||
<span style="display: inline-block" matTooltip='"Room" required' [matTooltipDisabled]="!!apiRoomName">
|
||||
<button mat-button id="get-room-api-btn" (click)="getRoom()" [disabled]="!apiRoomName">Get
|
||||
Room</button>
|
||||
</span>
|
||||
<span style="display: inline-block" matTooltip='"Room" required' [matTooltipDisabled]="!!apiRoomName">
|
||||
<button mat-button id="delete-room-api-btn" (click)="deleteRoom()" [disabled]="!apiRoomName">Delete
|
||||
Room</button>
|
||||
|
@ -53,6 +49,9 @@
|
|||
</span>
|
||||
<mat-checkbox class="subscriber-checkbox" name="subscriber" [(ngModel)]="muteTrack"
|
||||
[disabled]="!apiRoomName || !apiParticipantIdentity || !apiTrackSid">Mute</mat-checkbox>
|
||||
<span style="display: inline-block">
|
||||
<button mat-button id="delete-all-rooms-api-btn" (click)="deleteAllRooms()" style="font-style: italic; font-size: 0.75rem; margin-left: 5px;">Delete all</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
@ -79,10 +78,6 @@
|
|||
|
||||
<div class="button-group">
|
||||
<button mat-button id="list-egress-api-btn" (click)="listEgress()">List Egress</button>
|
||||
<span style="display: inline-block" matTooltip='"Egress ID" required' [matTooltipDisabled]="!!egressId">
|
||||
<button mat-button id="get-egress-api-btn" (click)="getEgress()" [disabled]="!egressId">Get
|
||||
Egress</button>
|
||||
</span>
|
||||
<span style="display: inline-block" matTooltip='"Room" required' [matTooltipDisabled]="!!egressRoomName">
|
||||
<button mat-button id="start-room-composite-egress-api-btn" (click)="startRoomCompositeEgress()"
|
||||
[disabled]="!egressRoomName">Start Room Composite Egress</button>
|
||||
|
@ -184,6 +179,9 @@
|
|||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<span style="display: inline-block">
|
||||
<button mat-button id="delete-all-ingress-api-btn" (click)="deleteAllIngress()" style="font-style: italic; font-size: 0.75rem; margin-left: 5px;">Delete all</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { MatChipInputEvent } from '@angular/material/chips';
|
|||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { LocalParticipant } from 'livekit-client';
|
||||
|
||||
import { EgressClient, EncodedFileOutput, EncodedFileType, EncodedOutputs, IngressInput, Room, RoomCompositeOptions, RoomServiceClient, SegmentedFileOutput, SegmentedFileProtocol, StreamOutput, StreamProtocol } from 'livekit-server-sdk';
|
||||
import { DirectFileOutput, EgressClient, EncodedFileOutput, EncodedFileType, EncodedOutputs, IngressInfo, IngressInput, Room, RoomCompositeOptions, RoomServiceClient, SegmentedFileOutput, SegmentedFileProtocol, StreamOutput, StreamProtocol } from 'livekit-server-sdk';
|
||||
import { RoomApiService } from 'src/app/services/room-api.service';
|
||||
|
||||
@Component({
|
||||
|
@ -44,11 +44,11 @@ export class RoomApiDialogComponent {
|
|||
|
||||
ingressRoomName: string;
|
||||
ingressId: string;
|
||||
inputTypeSelected: IngressInput = IngressInput.RTMP_INPUT;
|
||||
inputTypeSelected: IngressInput = IngressInput.URL_INPUT;
|
||||
INGRESS_INPUT_TYPES: { value: IngressInput, viewValue: string }[] = [
|
||||
{ value: IngressInput.URL_INPUT, viewValue: 'URL' },
|
||||
{ value: IngressInput.RTMP_INPUT, viewValue: 'RTMP' },
|
||||
{ value: IngressInput.WHIP_INPUT, viewValue: 'WHIP' },
|
||||
{ value: IngressInput.URL_INPUT, viewValue: 'URL' },
|
||||
];
|
||||
|
||||
response: string;
|
||||
|
@ -89,16 +89,6 @@ export class RoomApiDialogComponent {
|
|||
}
|
||||
}
|
||||
|
||||
async getRoom() {
|
||||
console.log('Getting room');
|
||||
try {
|
||||
const room = await this.roomApiService.getRoom(this.apiRoomName);
|
||||
this.response = JSON.stringify(room, null, 4);
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
}
|
||||
|
||||
async deleteRoom() {
|
||||
console.log('Deleting room');
|
||||
try {
|
||||
|
@ -110,6 +100,21 @@ export class RoomApiDialogComponent {
|
|||
}
|
||||
}
|
||||
|
||||
async deleteAllRooms() {
|
||||
console.log('Deleting all rooms');
|
||||
try {
|
||||
const promises: Promise<void>[] = [];
|
||||
const rooms = await this.roomApiService.listRooms();
|
||||
rooms.forEach(r => {
|
||||
promises.push(this.roomApiService.deleteRoom(r.name));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
this.response = 'Deleted ' + promises.length + ' rooms';
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
}
|
||||
|
||||
async listParticipants() {
|
||||
console.log('Listing participants');
|
||||
try {
|
||||
|
@ -161,16 +166,6 @@ export class RoomApiDialogComponent {
|
|||
}
|
||||
}
|
||||
|
||||
async getEgress() {
|
||||
console.log('Getting egress');
|
||||
try {
|
||||
const egress = await this.roomApiService.getEgress(this.egressId);
|
||||
this.response = JSON.stringify(egress, null, 4);
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
}
|
||||
|
||||
async startRoomCompositeEgress() {
|
||||
console.log('Starting room composite egress');
|
||||
try {
|
||||
|
@ -182,7 +177,7 @@ export class RoomApiDialogComponent {
|
|||
}
|
||||
const egress = await this.roomApiService.startRoomCompositeEgress(this.egressRoomName, roomCompositeOptions, encodedOutputs);
|
||||
this.response = JSON.stringify(egress, null, 4);
|
||||
this.egressId = egress.egress_id;
|
||||
this.egressId = egress.egressId;
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
|
@ -194,7 +189,7 @@ export class RoomApiDialogComponent {
|
|||
const encodedOutputs = this.getEncodedOutputs();
|
||||
const egress = await this.roomApiService.startTrackCompositeEgress(this.egressRoomName, this.audioTrackId, this.videoTrackId, encodedOutputs);
|
||||
this.response = JSON.stringify(egress, null, 4);
|
||||
this.egressId = egress.egress_id;
|
||||
this.egressId = egress.egressId;
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
|
@ -203,10 +198,9 @@ export class RoomApiDialogComponent {
|
|||
async startTrackEgress() {
|
||||
console.log('Starting track egress');
|
||||
try {
|
||||
const encodedOutputs = this.getEncodedOutputs();
|
||||
const egress = await this.roomApiService.startTrackEgress(this.egressRoomName, !!this.audioTrackId ? this.audioTrackId : this.videoTrackId, encodedOutputs);
|
||||
const egress = await this.roomApiService.startTrackEgress(this.egressRoomName, !!this.audioTrackId ? this.audioTrackId : this.videoTrackId);
|
||||
this.response = JSON.stringify(egress, null, 4);
|
||||
this.egressId = egress.egress_id;
|
||||
this.egressId = egress.egressId;
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
|
@ -237,7 +231,7 @@ export class RoomApiDialogComponent {
|
|||
try {
|
||||
const ingress = await this.roomApiService.createIngress(this.ingressRoomName, this.inputTypeSelected);
|
||||
this.response = JSON.stringify(ingress, null, 4);
|
||||
this.ingressId = ingress.ingress_id;
|
||||
this.ingressId = ingress.ingressId;
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
|
@ -253,6 +247,21 @@ export class RoomApiDialogComponent {
|
|||
}
|
||||
}
|
||||
|
||||
async deleteAllIngress() {
|
||||
console.log('Deleting all ingress');
|
||||
try {
|
||||
const promises: Promise<IngressInfo>[] = [];
|
||||
const ingresses = await this.roomApiService.listIngress();
|
||||
ingresses.forEach(i => {
|
||||
promises.push(this.roomApiService.deleteIngress(i.ingressId));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
this.response = 'Deleted ' + promises.length + ' ingresses';
|
||||
} catch (error: any) {
|
||||
this.response = 'Error [' + error.error.msg + ']';
|
||||
}
|
||||
}
|
||||
|
||||
addRtmpUrl(event: MatChipInputEvent): void {
|
||||
const value = (event.value || '').trim();
|
||||
if (value) {
|
||||
|
|
|
@ -1,202 +1,267 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AccessToken, EncodedOutputs, EncodingOptions, EncodingOptionsPreset, IngressInput, RoomCompositeOptions, VideoGrant } from 'livekit-server-sdk';
|
||||
import {
|
||||
AccessToken,
|
||||
CreateIngressOptions,
|
||||
DirectFileOutput,
|
||||
EgressClient,
|
||||
EgressInfo,
|
||||
EncodedOutputs,
|
||||
EncodingOptions,
|
||||
EncodingOptionsPreset,
|
||||
IngressClient,
|
||||
IngressInfo,
|
||||
IngressInput,
|
||||
IngressVideoEncodingPreset,
|
||||
ParticipantInfo,
|
||||
Room,
|
||||
RoomCompositeOptions,
|
||||
RoomServiceClient,
|
||||
TrackCompositeOptions,
|
||||
TrackInfo,
|
||||
TrackSource,
|
||||
VideoGrant,
|
||||
} from 'livekit-server-sdk';
|
||||
import { LivekitParamsService } from './livekit-params.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RoomApiService {
|
||||
private roomServiceClient: RoomServiceClient;
|
||||
private egressClient: EgressClient;
|
||||
private ingressClient: IngressClient;
|
||||
|
||||
private ADMIN_PERMISSIONS: VideoGrant = {
|
||||
roomCreate: true,
|
||||
roomList: true,
|
||||
roomRecord: true,
|
||||
roomAdmin: true,
|
||||
ingressAdmin: true,
|
||||
canPublish: true,
|
||||
canSubscribe: true,
|
||||
canPublishData: true,
|
||||
canUpdateOwnMetadata: true,
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private livekitParamsService: LivekitParamsService
|
||||
) {
|
||||
this.roomServiceClient = new RoomServiceClient(
|
||||
this.getRestUrl(),
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret
|
||||
);
|
||||
this.egressClient = new EgressClient(
|
||||
this.getRestUrl(),
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret
|
||||
);
|
||||
this.ingressClient = new IngressClient(
|
||||
this.getRestUrl(),
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret
|
||||
);
|
||||
}
|
||||
|
||||
async createToken(
|
||||
permissions: VideoGrant,
|
||||
participantName?: string,
|
||||
roomName?: string
|
||||
): Promise<string> {
|
||||
const at = new AccessToken(
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret,
|
||||
{ identity: participantName }
|
||||
);
|
||||
if (roomName) {
|
||||
permissions.room = roomName;
|
||||
}
|
||||
at.addGrant(permissions);
|
||||
return at.toJwt();
|
||||
}
|
||||
|
||||
/*
|
||||
* RoomService API
|
||||
* https://docs.livekit.io/reference/server/server-apis/
|
||||
*/
|
||||
|
||||
async listRooms(): Promise<Room[]> {
|
||||
return this.roomServiceClient.listRooms();
|
||||
}
|
||||
|
||||
async deleteRoom(roomName: string): Promise<void> {
|
||||
return await this.roomServiceClient.deleteRoom(roomName);
|
||||
}
|
||||
|
||||
async listParticipants(roomName: string): Promise<ParticipantInfo[]> {
|
||||
return await this.roomServiceClient.listParticipants(roomName);
|
||||
}
|
||||
|
||||
async getParticipant(
|
||||
roomName: string,
|
||||
participantIdentity: string
|
||||
): Promise<ParticipantInfo> {
|
||||
return await this.roomServiceClient.getParticipant(
|
||||
roomName,
|
||||
participantIdentity
|
||||
);
|
||||
}
|
||||
|
||||
async removeParticipant(
|
||||
roomName: string,
|
||||
participantIdentity: string
|
||||
): Promise<void> {
|
||||
return await this.roomServiceClient.removeParticipant(
|
||||
roomName,
|
||||
participantIdentity
|
||||
);
|
||||
}
|
||||
|
||||
async mutePublishedTrack(
|
||||
roomName: string,
|
||||
participantIdentity: string,
|
||||
track_sid: string,
|
||||
muted: boolean
|
||||
): Promise<TrackInfo> {
|
||||
return await this.roomServiceClient.mutePublishedTrack(
|
||||
roomName,
|
||||
participantIdentity,
|
||||
track_sid,
|
||||
muted
|
||||
);
|
||||
}
|
||||
|
||||
async listEgress(): Promise<EgressInfo[]> {
|
||||
return await this.egressClient.listEgress({});
|
||||
}
|
||||
|
||||
async startRoomCompositeEgress(
|
||||
roomName: string,
|
||||
roomCompositeOptions: RoomCompositeOptions,
|
||||
encodedOutputs: EncodedOutputs,
|
||||
encodingOptions?: EncodingOptionsPreset | EncodingOptions
|
||||
): Promise<EgressInfo> {
|
||||
if (encodedOutputs.file) {
|
||||
encodedOutputs.file.filepath = 'RoomComposite-{room_id}-{room_name}-{time}';
|
||||
}
|
||||
if (encodingOptions) {
|
||||
roomCompositeOptions.encodingOptions = encodingOptions;
|
||||
}
|
||||
return await this.egressClient.startRoomCompositeEgress(
|
||||
roomName,
|
||||
encodedOutputs,
|
||||
roomCompositeOptions
|
||||
);
|
||||
}
|
||||
|
||||
async startTrackCompositeEgress(
|
||||
roomName: string,
|
||||
audioTrackId: string,
|
||||
videoTrackId: string,
|
||||
encodedOutputs: EncodedOutputs,
|
||||
encodingOptions?: EncodingOptionsPreset | EncodingOptions
|
||||
): Promise<EgressInfo> {
|
||||
if (encodedOutputs.file) {
|
||||
encodedOutputs.file.filepath =
|
||||
'TrackComposite-{room_id}-{room_name}-{time}-{publisher_identity}';
|
||||
}
|
||||
const trackCompositeOptions: TrackCompositeOptions = {
|
||||
audioTrackId,
|
||||
videoTrackId,
|
||||
};
|
||||
|
||||
constructor(private http: HttpClient, private livekitParamsService: LivekitParamsService) { }
|
||||
|
||||
async createToken(permissions: VideoGrant, participantName?: string, roomName?: string): Promise<string> {
|
||||
const at = new AccessToken(this.livekitParamsService.getParams().livekitApiKey, this.livekitParamsService.getParams().livekitApiSecret, { identity: participantName });
|
||||
if (roomName) {
|
||||
permissions.room = roomName;
|
||||
}
|
||||
at.addGrant(permissions);
|
||||
return at.toJwt();
|
||||
if (encodingOptions) {
|
||||
trackCompositeOptions.encodingOptions = encodingOptions;
|
||||
}
|
||||
return await this.egressClient.startTrackCompositeEgress(
|
||||
roomName,
|
||||
encodedOutputs,
|
||||
trackCompositeOptions
|
||||
);
|
||||
}
|
||||
|
||||
private globalAdminToken(): Promise<string> {
|
||||
return this.createToken(this.ADMIN_PERMISSIONS, 'GLOBAL_ADMIN', undefined);
|
||||
async startTrackEgress(
|
||||
roomName: string,
|
||||
track_id: string,
|
||||
output?: DirectFileOutput | string
|
||||
): Promise<EgressInfo> {
|
||||
if (!output) {
|
||||
let outputAux = {
|
||||
filepath:
|
||||
'Track-{room_id}-{room_name}-{time}-{publisher_identity}-{track_id}-{track_type}-{track_source}',
|
||||
};
|
||||
output = outputAux as DirectFileOutput;
|
||||
}
|
||||
return await this.egressClient.startTrackEgress(roomName, output, track_id);
|
||||
}
|
||||
|
||||
private roomAdminToken(roomName: string): Promise<string> {
|
||||
return this.createToken(this.ADMIN_PERMISSIONS, 'ROOM_ADMIN', roomName);
|
||||
}
|
||||
async stopEgress(egressId: string): Promise<EgressInfo> {
|
||||
return await this.egressClient.stopEgress(egressId);
|
||||
}
|
||||
|
||||
/*
|
||||
* RoomService API
|
||||
* https://docs.livekit.io/reference/server/server-apis/
|
||||
*/
|
||||
async listIngress(): Promise<IngressInfo[]> {
|
||||
const ingressClient: IngressClient = new IngressClient(
|
||||
this.getRestUrl(),
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret
|
||||
);
|
||||
return await ingressClient.listIngress({});
|
||||
}
|
||||
|
||||
async listRooms() {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'ListRooms'), {}, this.getRestOptions(token)));
|
||||
}
|
||||
async createIngress(
|
||||
room_name: string,
|
||||
input_type: IngressInput
|
||||
): Promise<IngressInfo> {
|
||||
const ingressClient: IngressClient = new IngressClient(
|
||||
this.getRestUrl(),
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret
|
||||
);
|
||||
let options: CreateIngressOptions = {
|
||||
name: input_type + '-' + room_name,
|
||||
roomName: room_name,
|
||||
participantIdentity: 'IngressParticipantIdentity',
|
||||
participantName: 'MyIngress',
|
||||
participantMetadata: 'IngressParticipantMetadata',
|
||||
url: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
|
||||
// video: {
|
||||
// encodingOptions: {
|
||||
// video_codec: VideoCodec.VP8,
|
||||
// frame_rate: 30,
|
||||
// layers: [
|
||||
// {
|
||||
// quality: VideoQuality.HIGH,
|
||||
// width: 1920,
|
||||
// height: 1080,
|
||||
// bitrate: 4500000,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// } as any,
|
||||
video: {
|
||||
name: 'pelicula',
|
||||
source: TrackSource.SCREEN_SHARE,
|
||||
encodingOptions: {
|
||||
case: 'preset',
|
||||
value:
|
||||
IngressVideoEncodingPreset.H264_540P_25FPS_2_LAYERS_HIGH_MOTION,
|
||||
},
|
||||
} as any,
|
||||
// audio: {
|
||||
// source: TrackSource.MICROPHONE,
|
||||
// preset: IngressAudioEncodingPreset.OPUS_MONO_64KBS,
|
||||
// } as any,
|
||||
};
|
||||
const ingressInfo = await ingressClient.createIngress(input_type, options);
|
||||
return ingressInfo;
|
||||
}
|
||||
|
||||
async getRoom(roomName: string) {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'ListRooms'), { names: [roomName] }, this.getRestOptions(token)));
|
||||
}
|
||||
async deleteIngress(ingressId: string): Promise<IngressInfo> {
|
||||
const ingressClient: IngressClient = new IngressClient(
|
||||
this.getRestUrl(),
|
||||
this.livekitParamsService.getParams().livekitApiKey,
|
||||
this.livekitParamsService.getParams().livekitApiSecret
|
||||
);
|
||||
return await ingressClient.deleteIngress(ingressId);
|
||||
}
|
||||
|
||||
async deleteRoom(roomName: string) {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'DeleteRoom'), { room: roomName }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async listParticipants(roomName: string) {
|
||||
const token = await this.roomAdminToken(roomName);
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'ListParticipants'), { room: roomName }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async getParticipant(roomName: string, participantIdentity: string) {
|
||||
const token = await this.roomAdminToken(roomName);
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'GetParticipant'), { room: roomName, identity: participantIdentity }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async removeParticipant(roomName: string, participantIdentity: string) {
|
||||
const token = await this.roomAdminToken(roomName);
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'RemoveParticipant'), { room: roomName, identity: participantIdentity }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async mutePublishedTrack(roomName: string, participantIdentity: string, track_sid: string, muted: boolean) {
|
||||
const token = await this.roomAdminToken(roomName);
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('RoomService', 'MutePublishedTrack'), { room: roomName, identity: participantIdentity, track_sid, muted }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Egress API
|
||||
* https://docs.livekit.io/egress-ingress/egress/overview/#api
|
||||
*/
|
||||
|
||||
async listEgress() {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Egress', 'ListEgress'), {}, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async getEgress(egress_id: string) {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Egress', 'ListEgress'), { egress_id }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
// {room_id} {room_name} {time}
|
||||
async startRoomCompositeEgress(room_name: string, compositeOptions: RoomCompositeOptions, encodedOutputs: EncodedOutputs, encodingOptions?: EncodingOptionsPreset | EncodingOptions) {
|
||||
const token = await this.globalAdminToken();
|
||||
if (encodedOutputs.file) {
|
||||
encodedOutputs.file.filepath = 'track-{room_id}-{room_name}-{time}';
|
||||
}
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Egress', 'StartRoomCompositeEgress'), {
|
||||
room_name,
|
||||
layout: compositeOptions?.layout,
|
||||
audio_only: compositeOptions?.audioOnly,
|
||||
video_only: compositeOptions?.videoOnly,
|
||||
custom_base_url: compositeOptions?.customBaseUrl,
|
||||
file_outputs: encodedOutputs?.file ? [encodedOutputs?.file] : [],
|
||||
segment_outputs: encodedOutputs?.segments ? [encodedOutputs?.segments] : [],
|
||||
stream_outputs: encodedOutputs?.stream ? [encodedOutputs?.stream] : [],
|
||||
preset: encodingOptions
|
||||
}, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
// {room_id} {room_name} {time} {publisher_identity}
|
||||
async startTrackCompositeEgress(room_name: string, audio_track_id: string, video_track_id: string, encodedOutputs: EncodedOutputs, encodingOptions?: EncodingOptionsPreset | EncodingOptions) {
|
||||
const token = await this.globalAdminToken();
|
||||
if (encodedOutputs.file) {
|
||||
encodedOutputs.file.filepath = 'track-{room_id}-{room_name}-{time}-{publisher_identity}';
|
||||
}
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Egress', 'StartTrackCompositeEgress'), {
|
||||
room_name,
|
||||
audio_track_id,
|
||||
video_track_id,
|
||||
file_outputs: encodedOutputs?.file ? [encodedOutputs?.file] : [],
|
||||
segment_outputs: encodedOutputs?.segments ? [encodedOutputs?.segments] : [],
|
||||
stream_outputs: encodedOutputs?.stream ? [encodedOutputs?.stream] : [],
|
||||
preset: encodingOptions
|
||||
}, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
// {room_id} {room_name} {time} {publisher_identity} {track_id} {track_type} {track_source}
|
||||
async startTrackEgress(room_name: string, track_id: string, encodedOutputs: EncodedOutputs) {
|
||||
const token = await this.roomAdminToken(room_name);
|
||||
if (encodedOutputs.file) {
|
||||
encodedOutputs.file.filepath = 'track-{room_id}-{room_name}-{time}-{publisher_identity}-{track_id}-{track_type}-{track_source}';
|
||||
}
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Egress', 'StartTrackEgress'), {
|
||||
room_name,
|
||||
track_id,
|
||||
file: encodedOutputs?.file,
|
||||
// websocket_url: ""
|
||||
}, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async stopEgress(egress_id: string) {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Egress', 'StopEgress'), { egress_id }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ingress API
|
||||
* https://docs.livekit.io/egress-ingress/ingress/overview/#api
|
||||
*/
|
||||
|
||||
async listIngress() {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Ingress', 'ListIngress'), {}, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async createIngress(room_name: string, input_type: IngressInput) {
|
||||
const token = await this.roomAdminToken(room_name);
|
||||
let options = {
|
||||
room_name,
|
||||
input_type,
|
||||
name: 'MyIngress',
|
||||
participant_identity: 'IngressParticipantIdentity',
|
||||
participant_name: 'IngressParticipantName',
|
||||
url: 'http://playertest.longtailvideo.com/adaptive/wowzaid3/playlist.m3u8'
|
||||
}
|
||||
if (input_type === IngressInput.WHIP_INPUT) {
|
||||
(options as any).bypass_transcoding = true;
|
||||
}
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Ingress', 'CreateIngress'), options, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
async deleteIngress(ingress_id: string) {
|
||||
const token = await this.globalAdminToken();
|
||||
return await firstValueFrom<any>(this.http.post(this.getUrl('Ingress', 'DeleteIngress'), { ingress_id }, this.getRestOptions(token)));
|
||||
}
|
||||
|
||||
private getUrl(endpoint: string, method: string) {
|
||||
const wsUrl = this.livekitParamsService.getParams().livekitUrl;
|
||||
const protocol = (wsUrl.startsWith('wss:') || wsUrl.startsWith('https:')) ? 'https' : 'http';
|
||||
const restUrl = `${protocol}://${wsUrl.substring(wsUrl.indexOf('//') + 2).replace(/\/$/, "")}`;
|
||||
return `${restUrl}/twirp/livekit.${endpoint}/${method}`;
|
||||
}
|
||||
|
||||
private getRestOptions(token: string) {
|
||||
return {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private getRestUrl() {
|
||||
const wsUrl = this.livekitParamsService.getParams().livekitUrl;
|
||||
const protocol =
|
||||
wsUrl.startsWith('wss:') || wsUrl.startsWith('https:') ? 'https' : 'http';
|
||||
return `${protocol}://${wsUrl
|
||||
.substring(wsUrl.indexOf('//') + 2)
|
||||
.replace(/\/$/, '')}`;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue