From 18343fa47d0f50edada6801d4e2bf742b53d49ca Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Thu, 21 Nov 2024 14:54:49 +0100 Subject: [PATCH] openvidu-testapp: add CreateIngressOptions to dialog --- .../options-dialog.component.html | 2 +- .../room-api-dialog.component.css | 18 +- .../room-api-dialog.component.html | 39 +- .../room-api-dialog.component.ts | 573 ++++++++++-------- .../openvidu-instance.component.ts | 6 +- .../src/app/services/room-api.service.ts | 101 ++- 6 files changed, 448 insertions(+), 291 deletions(-) diff --git a/openvidu-testapp/src/app/components/dialogs/options-dialog/options-dialog.component.html b/openvidu-testapp/src/app/components/dialogs/options-dialog/options-dialog.component.html index dc14798a..295a48f2 100644 --- a/openvidu-testapp/src/app/components/dialogs/options-dialog/options-dialog.component.html +++ b/openvidu-testapp/src/app/components/dialogs/options-dialog/options-dialog.component.html @@ -151,7 +151,7 @@ videoCodec - {{codec}} + {{codec}} 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 1c48718c..0743aa8f 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 @@ -33,7 +33,7 @@ mat-dialog-content button { color: rgba(0, 0, 0, 0.54); font-weight: 400; margin-bottom: 5px; - margin-top: 13px + margin-top: 13px; } .inner-text-input { @@ -82,7 +82,7 @@ mat-checkbox ::ng-deep .mdc-checkbox__background { min-width: 22%; } -.egress-output-container>mat-checkbox { +.egress-output-container > mat-checkbox { width: 100%; margin-bottom: 7px; } @@ -120,4 +120,16 @@ mat-chip-row { .room-composite-options mat-checkbox { margin-left: 7px; -} \ No newline at end of file +} + +.ingress-options { + margin-bottom: 7px; +} + +#ingress-simulcast { + margin-right: 6px; +} + +#ingress-video-codec-select { + margin-right: 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 f2280846..bb92d642 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 @@ -163,9 +163,10 @@
- - + +
+ +
+ With audio + With video + + Simulcast + + + + Codec + + + {{codec.viewValue}} + + + + + + + Preset + + + {{preset.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 cb14d42f..c84ecd25 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 @@ -3,307 +3,384 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { Component, Inject, inject } from '@angular/core'; import { MatChipInputEvent } from '@angular/material/chips'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { VideoCodec } from '@livekit/protocol'; import { LocalParticipant } from 'livekit-client'; -import { DirectFileOutput, EgressClient, EncodedFileOutput, EncodedFileType, EncodedOutputs, IngressInfo, IngressInput, Room, RoomCompositeOptions, RoomServiceClient, SegmentedFileOutput, SegmentedFileProtocol, StreamOutput, StreamProtocol } from 'livekit-server-sdk'; +import { + DirectFileOutput, + EgressClient, + EncodedFileOutput, + EncodedFileType, + EncodedOutputs, + IngressInfo, + IngressInput, + IngressVideoEncodingPreset, + Room, + RoomCompositeOptions, + RoomServiceClient, + SegmentedFileOutput, + SegmentedFileProtocol, + StreamOutput, + StreamProtocol, +} from 'livekit-server-sdk'; import { RoomApiService } from 'src/app/services/room-api.service'; @Component({ - selector: 'app-room-api-dialog', - templateUrl: './room-api-dialog.component.html', - styleUrls: ['./room-api-dialog.component.css'] + selector: 'app-room-api-dialog', + templateUrl: './room-api-dialog.component.html', + styleUrls: ['./room-api-dialog.component.css'], }) export class RoomApiDialogComponent { + room: Room; + localParticipant: LocalParticipant; + roomServiceClient: RoomServiceClient; + egressClient: EgressClient; - room: Room; - localParticipant: LocalParticipant; - roomServiceClient: RoomServiceClient; - egressClient: EgressClient; + apiRoomName: string; + apiParticipantIdentity: string; + apiTrackSid: string; + muteTrack: boolean = true; - apiRoomName: string; - apiParticipantIdentity: string; - apiTrackSid: string; - muteTrack: boolean = true; + egressRoomName: string; + egressId: string; + audioTrackId: string; + videoTrackId: string; - egressRoomName: string; - egressId: string; - audioTrackId: string; - videoTrackId: string; + ROOM_COMPOSITE_LAYOUTS = ['grid', 'speaker', 'single-speaker']; + roomCompositeLayoutSelected: string = 'grid'; + roomCompositeAudioOnly: boolean = false; + roomCompositeVideoOnly: boolean = false; - ROOM_COMPOSITE_LAYOUTS = ['grid', 'speaker', 'single-speaker']; - roomCompositeLayoutSelected: string = 'grid'; - roomCompositeAudioOnly: boolean = false; - roomCompositeVideoOnly: boolean = false; + fileOutputSelected: boolean = true; + streamOutputSelected: boolean = false; + s3Endpoint: string = 'http://localhost:9100'; // 'http://minio:9000' + rtmpUrls: string[] = ['rtmp://172.17.0.1:1936/live/']; + segmentOutputSelected: boolean = false; + segmentDuration: number = 6; - fileOutputSelected: boolean = true; - streamOutputSelected: boolean = false; - s3Endpoint: string = 'http://localhost:9100'; // 'http://minio:9000' - rtmpUrls: string[] = ['rtmp://172.17.0.1:1936/live/'] - segmentOutputSelected: boolean = false; - segmentDuration: number = 6; + ingressRoomName: string; + ingressId: string; + inputTypeSelected: IngressInput = IngressInput.URL_INPUT; + ingressWithVideo: boolean = true; + ingressWithAudio: boolean = false; + ingressVideoCodecSelected: VideoCodec = VideoCodec.H264_BASELINE; + ingressSimulcast: boolean = true; + ingressVideoEncodingPresetSelected?: IngressVideoEncodingPreset = undefined; - ingressRoomName: string; - ingressId: string; - 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' }, - ]; + response: string; - response: string; + 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' }, + ]; + INGRESS_VIDEO_CODECS: { value: VideoCodec; viewValue: string }[] = [ + { value: VideoCodec.H264_BASELINE, viewValue: 'H264' }, + { value: VideoCodec.VP8, viewValue: 'VP8' }, + ]; + INGRESS_VIDEO_ENCODING_PRESETS: { + value: IngressInput | undefined; + viewValue: string; + }[] = [{ value: undefined, viewValue: 'undefined' }].concat( + Object.keys(IngressVideoEncodingPreset) + .filter((key) => isNaN(Number(key))) + .map((key) => { + return { + value: IngressVideoEncodingPreset[key as any], + viewValue: key.toString(), + } as any; + }) + ); - // s3Config = { - // endpoint: this.s3Endpoint, - // metadata: { "mytag": "myvalue" }, - // tagging: "mytagging" - // }; + // s3Config = { + // endpoint: this.s3Endpoint, + // metadata: { "mytag": "myvalue" }, + // tagging: "mytagging" + // }; - announcer = inject(LiveAnnouncer); - addOnBlur = true; - readonly separatorKeysCodes = [ENTER, COMMA] as const; + announcer = inject(LiveAnnouncer); + addOnBlur = true; + readonly separatorKeysCodes = [ENTER, COMMA] as const; - constructor( - private roomApiService: RoomApiService, - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any - ) { - this.room = data.room; - this.localParticipant = data.localParticipant; - this.apiRoomName = this.room?.name; - this.apiParticipantIdentity = this.localParticipant?.identity; - this.apiTrackSid = this.localParticipant?.videoTrackPublications.values().next().value?.trackSid!; - this.egressRoomName = this.room?.name; - this.audioTrackId = this.localParticipant?.audioTrackPublications.values().next().value?.trackSid!; - this.videoTrackId = this.localParticipant?.videoTrackPublications.values().next().value?.trackSid!; - this.ingressRoomName = this.room?.name; + constructor( + private roomApiService: RoomApiService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any + ) { + this.room = data.room; + this.localParticipant = data.localParticipant; + this.apiRoomName = this.room?.name; + this.apiParticipantIdentity = this.localParticipant?.identity; + this.apiTrackSid = this.localParticipant?.videoTrackPublications + .values() + .next().value?.trackSid!; + this.egressRoomName = this.room?.name; + this.audioTrackId = this.localParticipant?.audioTrackPublications + .values() + .next().value?.trackSid!; + this.videoTrackId = this.localParticipant?.videoTrackPublications + .values() + .next().value?.trackSid!; + this.ingressRoomName = this.room?.name; + } + + async listRooms() { + console.log('Listing rooms'); + try { + const rooms = await this.roomApiService.listRooms(); + this.response = JSON.stringify(rooms, null, 4); + } catch (error: any) { + this.response = error; } + } - async listRooms() { - console.log('Listing rooms'); - try { - const rooms = await this.roomApiService.listRooms(); - this.response = JSON.stringify(rooms, null, 4); - } catch (error: any) { - this.response = error; - } + async deleteRoom() { + console.log('Deleting room'); + try { + await this.roomApiService.deleteRoom(this.apiRoomName); + this.response = 'Room deleted'; + } catch (error: any) { + this.response = error; + console.log(JSON.stringify(error)); } + } - async deleteRoom() { - console.log('Deleting room'); - try { - await this.roomApiService.deleteRoom(this.apiRoomName); - this.response = 'Room deleted'; - } catch (error: any) { - this.response = error; - console.log(JSON.stringify(error)); - } + async deleteAllRooms() { + console.log('Deleting all rooms'); + try { + const promises: Promise[] = []; + 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; } + } - async deleteAllRooms() { - console.log('Deleting all rooms'); - try { - const promises: Promise[] = []; - 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; - } + async listParticipants() { + console.log('Listing participants'); + try { + const participants = await this.roomApiService.listParticipants( + this.apiRoomName + ); + this.response = JSON.stringify(participants, null, 4); + } catch (error: any) { + this.response = error; } + } - async listParticipants() { - console.log('Listing participants'); - try { - const participants = await this.roomApiService.listParticipants(this.apiRoomName); - this.response = JSON.stringify(participants, null, 4); - } catch (error: any) { - this.response = error; - } + async getParticipant() { + console.log('Getting participant'); + try { + const participant = await this.roomApiService.getParticipant( + this.apiRoomName, + this.apiParticipantIdentity + ); + this.response = JSON.stringify(participant, null, 4); + } catch (error: any) { + this.response = error; } + } - async getParticipant() { - console.log('Getting participant'); - try { - const participant = await this.roomApiService.getParticipant(this.apiRoomName, this.apiParticipantIdentity); - this.response = JSON.stringify(participant, null, 4); - } catch (error: any) { - this.response = error; - } + async removeParticipant() { + console.log('Removing participant'); + try { + await this.roomApiService.removeParticipant( + this.apiRoomName, + this.apiParticipantIdentity + ); + this.response = 'Participant removed'; + } catch (error: any) { + this.response = error; } + } - async removeParticipant() { - console.log('Removing participant'); - try { - await this.roomApiService.removeParticipant(this.apiRoomName, this.apiParticipantIdentity); - this.response = 'Participant removed'; - } catch (error: any) { - this.response = error; - } + async mutePublishedTrack() { + console.log(`${this.muteTrack ? 'Muting' : 'Unmuting'} track`); + try { + await this.roomApiService.mutePublishedTrack( + this.apiRoomName, + this.apiParticipantIdentity, + this.apiTrackSid, + this.muteTrack + ); + this.response = `Track ${this.muteTrack ? 'muted' : 'unmuted'}`; + this.muteTrack = !this.muteTrack; + } catch (error: any) { + this.response = error; } + } - async mutePublishedTrack() { - console.log(`${this.muteTrack ? 'Muting' : 'Unmuting'} track`); - try { - await this.roomApiService.mutePublishedTrack(this.apiRoomName, this.apiParticipantIdentity, this.apiTrackSid, this.muteTrack); - this.response = `Track ${this.muteTrack ? 'muted' : 'unmuted'}`; - this.muteTrack = !this.muteTrack; - } catch (error: any) { - this.response = error; - } + async listEgress() { + console.log('Listing egress'); + try { + const egress = await this.roomApiService.listEgress(); + this.response = JSON.stringify(egress, null, 4); + } catch (error: any) { + this.response = error; } + } - async listEgress() { - console.log('Listing egress'); - try { - const egress = await this.roomApiService.listEgress(); - this.response = JSON.stringify(egress, null, 4); - } catch (error: any) { - this.response = error; - } + async startRoomCompositeEgress() { + console.log('Starting room composite egress'); + try { + const encodedOutputs = this.getEncodedOutputs(); + const roomCompositeOptions: RoomCompositeOptions = { + layout: this.roomCompositeLayoutSelected, + audioOnly: this.roomCompositeAudioOnly, + videoOnly: this.roomCompositeVideoOnly, + }; + const egress = await this.roomApiService.startRoomCompositeEgress( + this.egressRoomName, + roomCompositeOptions, + encodedOutputs + ); + this.response = JSON.stringify(egress, null, 4); + this.egressId = egress.egressId; + } catch (error: any) { + this.response = error; } + } - async startRoomCompositeEgress() { - console.log('Starting room composite egress'); - try { - const encodedOutputs = this.getEncodedOutputs(); - const roomCompositeOptions: RoomCompositeOptions = { - layout: this.roomCompositeLayoutSelected, - audioOnly: this.roomCompositeAudioOnly, - videoOnly: this.roomCompositeVideoOnly - } - const egress = await this.roomApiService.startRoomCompositeEgress(this.egressRoomName, roomCompositeOptions, encodedOutputs); - this.response = JSON.stringify(egress, null, 4); - this.egressId = egress.egressId; - } catch (error: any) { - this.response = error; - } + async startTrackCompositeEgress() { + console.log('Starting track composite egress'); + try { + 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.egressId; + } catch (error: any) { + this.response = error; } + } - async startTrackCompositeEgress() { - console.log('Starting track composite egress'); - try { - 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.egressId; - } catch (error: any) { - this.response = error; - } + async startTrackEgress() { + console.log('Starting track egress'); + try { + const egress = await this.roomApiService.startTrackEgress( + this.egressRoomName, + !!this.audioTrackId ? this.audioTrackId : this.videoTrackId + ); + this.response = JSON.stringify(egress, null, 4); + this.egressId = egress.egressId; + } catch (error: any) { + this.response = error; } + } - async startTrackEgress() { - console.log('Starting track egress'); - try { - const egress = await this.roomApiService.startTrackEgress(this.egressRoomName, !!this.audioTrackId ? this.audioTrackId : this.videoTrackId); - this.response = JSON.stringify(egress, null, 4); - this.egressId = egress.egressId; - } catch (error: any) { - this.response = error; - } + async stopEgress() { + console.log('Stopping egress'); + try { + await this.roomApiService.stopEgress(this.egressId); + this.response = 'Egress stopped'; + } catch (error: any) { + this.response = error; } + } - async stopEgress() { - console.log('Stopping egress'); - try { - await this.roomApiService.stopEgress(this.egressId); - this.response = 'Egress stopped'; - } catch (error: any) { - this.response = error; - } + async listIngress() { + console.log('Listing ingress'); + try { + const ingress = await this.roomApiService.listIngress(); + this.response = JSON.stringify(ingress, null, 4); + } catch (error: any) { + this.response = error; } + } - async listIngress() { - console.log('Listing ingress'); - try { - const ingress = await this.roomApiService.listIngress(); - this.response = JSON.stringify(ingress, null, 4); - } catch (error: any) { - this.response = error; - } + async createIngress() { + console.log('Creating ingress'); + try { + const ingress = await this.roomApiService.createIngress( + this.ingressRoomName, + this.inputTypeSelected, + this.ingressWithAudio, + this.ingressWithVideo, + this.ingressVideoCodecSelected, + this.ingressSimulcast, + this.ingressVideoEncodingPresetSelected + ); + this.response = JSON.stringify(ingress, null, 4); + this.ingressId = ingress.ingressId; + } catch (error: any) { + this.response = error; + console.warn(error); + console.warn(error.code); + console.warn(error.msg); } + } - async createIngress() { - console.log('Creating ingress'); - try { - const ingress = await this.roomApiService.createIngress(this.ingressRoomName, this.inputTypeSelected); - this.response = JSON.stringify(ingress, null, 4); - this.ingressId = ingress.ingressId; - } catch (error: any) { - this.response = error; - console.warn(error); - console.warn(error.code); - console.warn(error.msg); - } + async deleteIngress() { + console.log('Deleting ingress'); + try { + await this.roomApiService.deleteIngress(this.ingressId); + this.response = 'Ingress deleted'; + } catch (error: any) { + this.response = error; } + } - async deleteIngress() { - console.log('Deleting ingress'); - try { - await this.roomApiService.deleteIngress(this.ingressId); - this.response = 'Ingress deleted'; - } catch (error: any) { - this.response = error; - } + async deleteAllIngress() { + console.log('Deleting all ingress'); + try { + const promises: Promise[] = []; + 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; } + } - async deleteAllIngress() { - console.log('Deleting all ingress'); - try { - const promises: Promise[] = []; - 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; - } + addRtmpUrl(event: MatChipInputEvent): void { + const value = (event.value || '').trim(); + if (value) { + this.rtmpUrls.push(value); } + event.chipInput!.clear(); + } - addRtmpUrl(event: MatChipInputEvent): void { - const value = (event.value || '').trim(); - if (value) { - this.rtmpUrls.push(value); - } - event.chipInput!.clear(); + removeRtmpUrl(url: string): void { + const index = this.rtmpUrls.indexOf(url); + if (index >= 0) { + this.rtmpUrls.splice(index, 1); + this.announcer.announce(`Removed ${url}`); } + } - removeRtmpUrl(url: string): void { - const index = this.rtmpUrls.indexOf(url); - if (index >= 0) { - this.rtmpUrls.splice(index, 1); - this.announcer.announce(`Removed ${url}`); - } + private getEncodedOutputs(): EncodedOutputs { + // this.s3Config.endpoint = this.s3Endpoint; + const encodedOutputs: EncodedOutputs = {}; + if (this.fileOutputSelected) { + encodedOutputs.file = new EncodedFileOutput({ + fileType: EncodedFileType.DEFAULT_FILETYPE, + filepath: 'room-composite-{room_id}-{room_name}-{time}', + }); } - - private getEncodedOutputs(): EncodedOutputs { - // this.s3Config.endpoint = this.s3Endpoint; - const encodedOutputs: EncodedOutputs = {}; - if (this.fileOutputSelected) { - encodedOutputs.file = new EncodedFileOutput({ - fileType: EncodedFileType.DEFAULT_FILETYPE, - filepath: 'room-composite-{room_id}-{room_name}-{time}', - }); - } - if (this.streamOutputSelected) { - encodedOutputs.stream = new StreamOutput({ - urls: this.rtmpUrls, - protocol: StreamProtocol.RTMP - }); - } - if (this.segmentOutputSelected) { - encodedOutputs.segments = new SegmentedFileOutput({ - protocol: SegmentedFileProtocol.HLS_PROTOCOL, - segmentDuration: this.segmentDuration, - // s3: this.s3Config - }); - } - return encodedOutputs; + if (this.streamOutputSelected) { + encodedOutputs.stream = new StreamOutput({ + urls: this.rtmpUrls, + protocol: StreamProtocol.RTMP, + }); } - + if (this.segmentOutputSelected) { + encodedOutputs.segments = new SegmentedFileOutput({ + protocol: SegmentedFileProtocol.HLS_PROTOCOL, + segmentDuration: this.segmentDuration, + // s3: this.s3Config + }); + } + return encodedOutputs; + } } diff --git a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts index 13814263..79dafe54 100644 --- a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts +++ b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts @@ -80,11 +80,11 @@ export class OpenviduInstanceComponent { autoSubscribe: false, }; createLocalTracksOptions: CreateLocalTracksOptions = { - audio: true, + audio: false, video: { resolution: { - width: 640, - height: 480, + width: 1920, + height: 1080, frameRate: 30, }, }, diff --git a/openvidu-testapp/src/app/services/room-api.service.ts b/openvidu-testapp/src/app/services/room-api.service.ts index 538ce548..24a685f3 100644 --- a/openvidu-testapp/src/app/services/room-api.service.ts +++ b/openvidu-testapp/src/app/services/room-api.service.ts @@ -21,10 +21,15 @@ import { RoomServiceClient, TrackCompositeOptions, TrackInfo, - TrackSource, VideoGrant, } from 'livekit-server-sdk'; import { LivekitParamsService } from './livekit-params.service'; +import { VideoQuality } from 'livekit-client'; +import { + IngressVideoEncodingOptions, + VideoCodec, + VideoLayer, +} from '@livekit/protocol'; @Injectable({ providedIn: 'root', @@ -134,7 +139,8 @@ export class RoomApiService { encodingOptions?: EncodingOptionsPreset | EncodingOptions ): Promise { if (encodedOutputs.file) { - encodedOutputs.file.filepath = 'RoomComposite-{room_id}-{room_name}-{time}'; + encodedOutputs.file.filepath = + 'RoomComposite-{room_id}-{room_name}-{time}'; } if (encodingOptions) { roomCompositeOptions.encodingOptions = encodingOptions; @@ -201,49 +207,78 @@ export class RoomApiService { async createIngress( room_name: string, - input_type: IngressInput + input_type: IngressInput, + withAudio: boolean, + withVideo: boolean, + codec: VideoCodec, + simulcast: boolean, + preset?: IngressVideoEncodingPreset ): Promise { - const ingressClient: IngressClient = new IngressClient( - this.getRestUrl(), - this.livekitParamsService.getParams().livekitApiKey, - this.livekitParamsService.getParams().livekitApiSecret - ); + let url; + if (!withVideo) { + url = + 'https://s3.eu-west-1.amazonaws.com/public.openvidu.io/bbb_sunflower_1080p_60fps_normal_onlyaudio.mp3'; + } else { + url = withAudio + ? 'https://s3.eu-west-1.amazonaws.com/public.openvidu.io/bbb_sunflower_1080p_60fps_normal.mp4' + : 'https://s3.eu-west-1.amazonaws.com/public.openvidu.io/bbb_sunflower_1080p_60fps_normal_noaudio.mp4'; + } 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, + url, video: { - name: 'pelicula', - source: TrackSource.SCREEN_SHARE, encodingOptions: { - case: 'preset', - value: - IngressVideoEncodingPreset.H264_540P_25FPS_2_LAYERS_HIGH_MOTION, + case: preset != undefined ? 'preset' : 'options', + value: {}, }, } as any, - // audio: { - // source: TrackSource.MICROPHONE, - // preset: IngressAudioEncodingPreset.OPUS_MONO_64KBS, - // } as any, }; - const ingressInfo = await ingressClient.createIngress(input_type, options); + if (preset != undefined) { + options.video!.encodingOptions.value = preset; + } else { + const encodingOptions = options.video!.encodingOptions + .value! as IngressVideoEncodingOptions; + encodingOptions.videoCodec = codec; + encodingOptions.frameRate = 30; + let layers: VideoLayer[] = []; + if (simulcast) { + layers = [ + { + quality: VideoQuality.HIGH, + width: 1920, + height: 1080, + }, + { + quality: VideoQuality.MEDIUM, + width: 1280, + height: 720, + }, + { + quality: VideoQuality.LOW, + width: 640, + height: 360, + }, + ] as VideoLayer[]; + } else { + layers = [ + { + quality: VideoQuality.HIGH, + width: 1920, + height: 1080, + } as VideoLayer, + ]; + } + encodingOptions.layers = layers; + } + + const ingressInfo = await this.ingressClient.createIngress( + input_type, + options + ); return ingressInfo; }