openvidu-testapp: upgrade to Angular v20

master
pabloFuente 2025-10-07 22:00:11 +02:00
parent 6a5980e3da
commit 780635dc9a
16 changed files with 4982 additions and 2367 deletions

View File

@ -73,13 +73,13 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"builder": "@angular/build:extract-i18n",
"options": {
"buildTarget": "openvidu-testapp-livekit:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"builder": "@angular/build:karma",
"options": {
"polyfills": [
"zone.js",
@ -103,5 +103,31 @@
},
"cli": {
"analytics": false
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -11,16 +11,16 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^19.2.14",
"@angular/animations": "^20.3.3",
"@angular/cdk": "^19.2.18",
"@angular/common": "^19.2.14",
"@angular/compiler": "^19.2.14",
"@angular/core": "^19.2.14",
"@angular/forms": "^19.2.14",
"@angular/common": "^20.3.3",
"@angular/compiler": "^20.3.3",
"@angular/core": "^20.3.3",
"@angular/forms": "^20.3.3",
"@angular/material": "^19.2.18",
"@angular/platform-browser": "^19.2.14",
"@angular/platform-browser-dynamic": "^19.2.14",
"@angular/router": "^19.2.14",
"@angular/platform-browser": "^20.3.3",
"@angular/platform-browser-dynamic": "^20.3.3",
"@angular/router": "^20.3.3",
"@livekit/protocol": "^1.38.0",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.1",
@ -36,9 +36,9 @@
},
"devDependencies": {
"@angular-builders/custom-webpack": "^19.0.1",
"@angular-devkit/build-angular": "^19.2.15",
"@angular/cli": "~19.2.15",
"@angular/compiler-cli": "^19.2.14",
"@angular/build": "^20.3.4",
"@angular/cli": "~20.3.4",
"@angular/compiler-cli": "^20.3.3",
"@types/events": "^3.0.3",
"@types/jasmine": "~5.1.8",
"@types/json-stringify-safe": "^5.0.3",
@ -52,4 +52,4 @@
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "5.8.3"
}
}
}

View File

@ -1,16 +1,20 @@
<div class="parent-div">
<audio #mediaElement [id]="finalElementRefId" [ngClass]="getTrackOrigin()"></audio>
<span>{{trackPublication.source}}</span>
<div class="bottom-div">
<button *ngIf="localParticipant" (click)="muteUnmuteAudio()" class="audio-btn" matTooltip="Mute/Unmute audio"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Mute/Unmute audio" class="mat-icon material-icons" role="img"
aria-hidden="true">{{muteAudioIcon}}</mat-icon>
</button>
<button *ngIf="localParticipant" (click)="unpublishTrack()" class="audio-btn" matTooltip="Unpublish track"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Unpublish track" class="mat-icon material-icons" role="img"
aria-hidden="true">stop</mat-icon>
</button>
</div>
<audio #mediaElement [id]="finalElementRefId" [ngClass]="getTrackOrigin()"></audio>
<span>{{trackPublication.source}}</span>
<div class="bottom-div">
@if (localParticipant) {
<button (click)="muteUnmuteAudio()" class="audio-btn" matTooltip="Mute/Unmute audio"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Mute/Unmute audio" class="mat-icon material-icons" role="img"
aria-hidden="true">{{muteAudioIcon}}</mat-icon>
</button>
}
@if (localParticipant) {
<button (click)="unpublishTrack()" class="audio-btn" matTooltip="Unpublish track"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Unpublish track" class="mat-icon material-icons" role="img"
aria-hidden="true">stop</mat-icon>
</button>
}
</div>
</div>

View File

@ -7,35 +7,39 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
template: `
<h2 mat-dialog-title>{{target}} events</h2>
<mat-dialog-content>
<mat-slide-toggle [(ngModel)]="checkAll" (change)="updateAll()" [color]="'warn'"><i>ALL</i></mat-slide-toggle>
<mat-divider></mat-divider>
<div class="row no-wrap-row">
<div class="col-50">
<div *ngFor="let event of eventArray | slice:0:(eventArray.length/2)" class="toggle">
<mat-slide-toggle
(change)="toggleEvent($event)"
[checked]="eventCollection.get(event)"
[name]="event"
color="warn">{{event}}
</mat-slide-toggle>
</div>
</div>
<div class="col-50">
<div *ngFor="let event of eventArray | slice:(eventArray.length/2 + 1):(eventArray.length)" class="toggle">
<mat-slide-toggle
(change)="toggleEvent($event)"
[checked]="eventCollection.get(event)"
[name]="event"
color="warn">{{event}}
</mat-slide-toggle>
</div>
<mat-slide-toggle [(ngModel)]="checkAll" (change)="updateAll()" [color]="'warn'"><i>ALL</i></mat-slide-toggle>
<mat-divider></mat-divider>
<div class="row no-wrap-row">
<div class="col-50">
@for (event of eventArray | slice:0:(eventArray.length/2); track event) {
<div class="toggle">
<mat-slide-toggle
(change)="toggleEvent($event)"
[checked]="eventCollection.get(event)"
[name]="event"
color="warn">{{event}}
</mat-slide-toggle>
</div>
}
</div>
<div class="col-50">
@for (event of eventArray | slice:(eventArray.length/2 + 1):(eventArray.length); track event) {
<div class="toggle">
<mat-slide-toggle
(change)="toggleEvent($event)"
[checked]="eventCollection.get(event)"
[name]="event"
color="warn">{{event}}
</mat-slide-toggle>
</div>
}
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button id="close-dialog-btn" mat-dialog-close="">CLOSE</button>
<button mat-button id="close-dialog-btn" mat-dialog-close="">CLOSE</button>
</mat-dialog-actions>
`,
`,
styles: [
'mat-dialog-content { display: inline; }',
'mat-divider { margin-top: 5px; margin-bottom: 5px; }',

View File

@ -1,6 +1,8 @@
<div>
<h2 mat-dialog-title>{{ title }}</h2>
<p *ngIf="subtitle" id="subtitle">{{ subtitle }}</p>
@if (subtitle) {
<p id="subtitle">{{ subtitle }}</p>
}
<mat-dialog-content>
<mat-form-field>

View File

@ -1,182 +1,238 @@
<div>
<h2 mat-dialog-title>OPTIONS</h2>
<mat-dialog-content>
<mat-divider *ngIf="roomOptions"></mat-divider>
<div *ngIf="roomOptions">
<label><a href="https://docs.livekit.io/client-sdk-js/interfaces/RoomOptions.html" target="_blank">RoomOptions</a></label> / <label><a href="https://docs.livekit.io/client-sdk-js/interfaces/RoomConnectOptions.html" target="_blank">RoomConnectOptions</a></label><br>
<mat-checkbox id="room-adaptiveStream" [(ngModel)]="roomOptions.adaptiveStream">adaptiveStream</mat-checkbox>
<mat-checkbox id="room-dynacast" [(ngModel)]="roomOptions.dynacast">dynacast</mat-checkbox>
<mat-checkbox id="room-disconnectOnPageLeave" [(ngModel)]="roomOptions.disconnectOnPageLeave">disconnectOnPageLeave</mat-checkbox>
<mat-checkbox id="room-stopLocalTrackOnUnpublish" [(ngModel)]="roomOptions.stopLocalTrackOnUnpublish">stopLocalTrackOnUnpublish</mat-checkbox>
<mat-checkbox id="room-webAudioMix" [(ngModel)]="roomOptions.webAudioMix">webAudioMix</mat-checkbox>
<mat-checkbox id="room-forceRelay" [(ngModel)]="forceRelay">Force relay candidates</mat-checkbox>
</div>
<mat-divider *ngIf="createLocalTracksOptions"></mat-divider>
<div *ngIf="createLocalTracksOptions">
<div *ngIf="createLocalTracksOptions.video !== undefined">
<a href="https://docs.livekit.io/client-sdk-js/interfaces/VideoCaptureOptions.html" target="_blank">VideoCaptureOptions</a>
<mat-radio-group [(ngModel)]="videoOption">
<mat-radio-button [value]="true" id="video-capture-true">True (default)</mat-radio-button>
<mat-radio-button *ngIf="allowDisablingVideo" [value]="false" id="video-capture-false">False (no video)</mat-radio-button>
<mat-radio-button [value]="'custom'" id="video-capture-custom">Custom</mat-radio-button>
</mat-radio-group>
<div *ngIf="videoOption === 'custom'">
<mat-form-field id="video-deviceId">
<mat-label>deviceId</mat-label>
<mat-select [(value)]="auxVideoCaptureOptions.deviceId">
<mat-option *ngFor="let device of inputVideoDevices" [value]="{ exact: device.deviceId }">{{'[' + device.label + '] ' + device.deviceId}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="video-facingMode">
<mat-label>facingMode</mat-label>
<mat-select [(value)]="auxVideoCaptureOptions.facingMode">
<mat-option *ngFor="let mode of ['user','environment','left','right']" [value]="mode">{{mode}}</mat-option>
</mat-select>
</mat-form-field>
<app-video-resolution style="display: inline-block;"
[componentId]="'resolution-video-capture-options'"
[width]="auxVideoCaptureOptions.resolution!.width"
[height]="auxVideoCaptureOptions.resolution!.height"
[frameRate]="auxVideoCaptureOptions.resolution!.frameRate"
[aspectRatio]="auxVideoCaptureOptions.resolution!.aspectRatio"
(resolutionChanged)="auxVideoCaptureOptions.resolution!.width = $event.width; auxVideoCaptureOptions.resolution!.height = $event.height; auxVideoCaptureOptions.resolution!.frameRate = $event.frameRate; auxVideoCaptureOptions.resolution!.aspectRatio = $event.aspectRatio">
</app-video-resolution>
</div>
@if (roomOptions) {
<mat-divider></mat-divider>
}
@if (roomOptions) {
<div>
<label><a href="https://docs.livekit.io/client-sdk-js/interfaces/RoomOptions.html" target="_blank">RoomOptions</a></label> / <label><a href="https://docs.livekit.io/client-sdk-js/interfaces/RoomConnectOptions.html" target="_blank">RoomConnectOptions</a></label><br>
<mat-checkbox id="room-adaptiveStream" [(ngModel)]="roomOptions.adaptiveStream">adaptiveStream</mat-checkbox>
<mat-checkbox id="room-dynacast" [(ngModel)]="roomOptions.dynacast">dynacast</mat-checkbox>
<mat-checkbox id="room-disconnectOnPageLeave" [(ngModel)]="roomOptions.disconnectOnPageLeave">disconnectOnPageLeave</mat-checkbox>
<mat-checkbox id="room-stopLocalTrackOnUnpublish" [(ngModel)]="roomOptions.stopLocalTrackOnUnpublish">stopLocalTrackOnUnpublish</mat-checkbox>
<mat-checkbox id="room-webAudioMix" [(ngModel)]="roomOptions.webAudioMix">webAudioMix</mat-checkbox>
<mat-checkbox id="room-forceRelay" [(ngModel)]="forceRelay">Force relay candidates</mat-checkbox>
</div>
<div *ngIf="createLocalTracksOptions.audio !== undefined" style="margin-top: 16px">
<label class="label"><a href="https://docs.livekit.io/client-sdk-js/interfaces/AudioCaptureOptions.html" target="_blank">AudioCaptureOptions</a></label>
<mat-radio-group [(ngModel)]="audioOption">
<mat-radio-button [value]="true" id="audio-capture-true">True (default)</mat-radio-button>
<mat-radio-button *ngIf="allowDisablingAudio" [value]="false" id="audio-capture-false">False (no audio)</mat-radio-button>
<mat-radio-button [value]="'custom'" id="audio-capture-custom">Custom</mat-radio-button>
</mat-radio-group>
<div *ngIf="audioOption === 'custom'">
}
@if (createLocalTracksOptions) {
<mat-divider></mat-divider>
}
@if (createLocalTracksOptions) {
<div>
@if (createLocalTracksOptions.video !== undefined) {
<div>
<mat-checkbox id="audio-autoGainControl" [(ngModel)]="auxAudioCaptureOptions.autoGainControl">autoGainControl</mat-checkbox>
<mat-checkbox id="audio-echoCancellation" [(ngModel)]="auxAudioCaptureOptions.echoCancellation">echoCancellation</mat-checkbox>
<mat-checkbox id="audio-noiseSuppression" [(ngModel)]="auxAudioCaptureOptions.noiseSuppression">noiseSuppression</mat-checkbox>
<a href="https://docs.livekit.io/client-sdk-js/interfaces/VideoCaptureOptions.html" target="_blank">VideoCaptureOptions</a>
<mat-radio-group [(ngModel)]="videoOption">
<mat-radio-button [value]="true" id="video-capture-true">True (default)</mat-radio-button>
@if (allowDisablingVideo) {
<mat-radio-button [value]="false" id="video-capture-false">False (no video)</mat-radio-button>
}
<mat-radio-button [value]="'custom'" id="video-capture-custom">Custom</mat-radio-button>
</mat-radio-group>
@if (videoOption === 'custom') {
<div>
<mat-form-field id="video-deviceId">
<mat-label>deviceId</mat-label>
<mat-select [(value)]="auxVideoCaptureOptions.deviceId">
@for (device of inputVideoDevices; track device) {
<mat-option [value]="{ exact: device.deviceId }">{{'[' + device.label + '] ' + device.deviceId}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field id="video-facingMode">
<mat-label>facingMode</mat-label>
<mat-select [(value)]="auxVideoCaptureOptions.facingMode">
@for (mode of ['user','environment','left','right']; track mode) {
<mat-option [value]="mode">{{mode}}</mat-option>
}
</mat-select>
</mat-form-field>
<app-video-resolution style="display: inline-block;"
[componentId]="'resolution-video-capture-options'"
[width]="auxVideoCaptureOptions.resolution!.width"
[height]="auxVideoCaptureOptions.resolution!.height"
[frameRate]="auxVideoCaptureOptions.resolution!.frameRate"
[aspectRatio]="auxVideoCaptureOptions.resolution!.aspectRatio"
(resolutionChanged)="auxVideoCaptureOptions.resolution!.width = $event.width; auxVideoCaptureOptions.resolution!.height = $event.height; auxVideoCaptureOptions.resolution!.frameRate = $event.frameRate; auxVideoCaptureOptions.resolution!.aspectRatio = $event.aspectRatio">
</app-video-resolution>
</div>
}
</div>
<mat-form-field class="inner-text-input">
<mat-label>deviceId</mat-label>
<input matInput id="audio-deviceId" placeholder="deviceId" [(ngModel)]="auxAudioCaptureOptions.deviceId"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>channelCount</mat-label>
<input matInput id="audio-channelCount" type="number" placeholder="channelCount" [(ngModel)]="auxAudioCaptureOptions.channelCount"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>latency</mat-label>
<input matInput id="audio-latency" type="number" placeholder="latency" [(ngModel)]="auxAudioCaptureOptions.latency"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>sampleRate</mat-label>
<input matInput id="audio-sampleRate" type="number" placeholder="sampleRate" [(ngModel)]="auxAudioCaptureOptions.sampleRate"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>sampleSize</mat-label>
<input matInput id="audio-sampleSize" type="number" placeholder="sampleSize" [(ngModel)]="auxAudioCaptureOptions.sampleSize"/>
</mat-form-field>
</div>
}
@if (createLocalTracksOptions.audio !== undefined) {
<div style="margin-top: 16px">
<label class="label"><a href="https://docs.livekit.io/client-sdk-js/interfaces/AudioCaptureOptions.html" target="_blank">AudioCaptureOptions</a></label>
<mat-radio-group [(ngModel)]="audioOption">
<mat-radio-button [value]="true" id="audio-capture-true">True (default)</mat-radio-button>
@if (allowDisablingAudio) {
<mat-radio-button [value]="false" id="audio-capture-false">False (no audio)</mat-radio-button>
}
<mat-radio-button [value]="'custom'" id="audio-capture-custom">Custom</mat-radio-button>
</mat-radio-group>
@if (audioOption === 'custom') {
<div>
<div>
<mat-checkbox id="audio-autoGainControl" [(ngModel)]="auxAudioCaptureOptions.autoGainControl">autoGainControl</mat-checkbox>
<mat-checkbox id="audio-echoCancellation" [(ngModel)]="auxAudioCaptureOptions.echoCancellation">echoCancellation</mat-checkbox>
<mat-checkbox id="audio-noiseSuppression" [(ngModel)]="auxAudioCaptureOptions.noiseSuppression">noiseSuppression</mat-checkbox>
</div>
<mat-form-field class="inner-text-input">
<mat-label>deviceId</mat-label>
<input matInput id="audio-deviceId" placeholder="deviceId" [(ngModel)]="auxAudioCaptureOptions.deviceId"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>channelCount</mat-label>
<input matInput id="audio-channelCount" type="number" placeholder="channelCount" [(ngModel)]="auxAudioCaptureOptions.channelCount"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>latency</mat-label>
<input matInput id="audio-latency" type="number" placeholder="latency" [(ngModel)]="auxAudioCaptureOptions.latency"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>sampleRate</mat-label>
<input matInput id="audio-sampleRate" type="number" placeholder="sampleRate" [(ngModel)]="auxAudioCaptureOptions.sampleRate"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>sampleSize</mat-label>
<input matInput id="audio-sampleSize" type="number" placeholder="sampleSize" [(ngModel)]="auxAudioCaptureOptions.sampleSize"/>
</mat-form-field>
</div>
}
</div>
}
</div>
</div>
<mat-divider *ngIf="shareScreen"></mat-divider>
<div *ngIf="shareScreen">
<label><a href="https://docs.livekit.io/client-sdk-js/interfaces/ScreenShareCaptureOptions.html" target="_blank">ScreenShareCaptureOptions</a></label><br>
<mat-radio-group [(ngModel)]="screenOption" (change)="screenOptionChanged($event)">
<mat-radio-button [value]="true">True (default)</mat-radio-button>
<mat-radio-button [value]="false" *ngIf="allowDisablingScreen">False (no screen)</mat-radio-button>
<mat-radio-button [value]="'custom'">Custom</mat-radio-button>
</mat-radio-group>
<div *ngIf="screenOption == 'custom'">
<mat-checkbox id="screenShare-video" [(ngModel)]="screenShareCaptureOptions!.video">video</mat-checkbox>
<mat-checkbox id="screenShare-audio" [(ngModel)]="screenShareCaptureOptions!.audio">audio</mat-checkbox>
<mat-checkbox id="screenShare-preferCurrentTab" [(ngModel)]="screenShareCaptureOptions!.preferCurrentTab">preferCurrentTab</mat-checkbox>
<mat-checkbox id="screenShare-suppressLocalAudioPlayback" [(ngModel)]="screenShareCaptureOptions!.suppressLocalAudioPlayback">suppressLocalAudioPlayback</mat-checkbox>
<mat-form-field *ngIf="screenShareCaptureOptions!.video" id="screenShare-displaySurface">
<mat-label>displaySurface</mat-label>
<mat-select [(value)]="auxScreenDisplaySurface">
<mat-option *ngFor="let surface of ['NONE','window','browser','monitor']" [value]="surface">{{surface}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-contentHint">
<mat-label>contentHint</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.contentHint">
<mat-option *ngFor="let hint of ['text','detail','motion']" [value]="hint">{{hint}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-selfBrowserSurface">
<mat-label>selfBrowserSurface</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.selfBrowserSurface">
<mat-option *ngFor="let surface of ['include','exclude']" [value]="surface">{{surface}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-surfaceSwitching">
<mat-label>surfaceSwitching</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.surfaceSwitching">
<mat-option *ngFor="let surface of ['include','exclude']" [value]="surface">{{surface}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-systemAudio">
<mat-label>systemAudio</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.systemAudio">
<mat-option *ngFor="let audio of ['include','exclude']" [value]="audio">{{audio}}</mat-option>
</mat-select>
</mat-form-field>
<div>
<label>Resolution</label>
<mat-radio-group [(ngModel)]="customScreenShareResolution" (change)="handleCustomScreenResolutionChange()">
<mat-radio-button [value]="false">Default</mat-radio-button>
<mat-radio-button [value]="true">Custom</mat-radio-button>
</mat-radio-group>
<app-video-resolution *ngIf="customScreenShareResolution"
[componentId]="'resolution-screen-capture-options'"
[showTitle]="false"
[width]="screenShareCaptureOptions!.resolution!.width"
[height]="screenShareCaptureOptions!.resolution!.height"
[frameRate]="screenShareCaptureOptions!.resolution!.frameRate"
[aspectRatio]="screenShareCaptureOptions!.resolution!.aspectRatio"
(resolutionChanged)="screenShareCaptureOptions!.resolution!.width = $event.width; screenShareCaptureOptions!.resolution!.height = $event.height; screenShareCaptureOptions!.resolution!.frameRate = $event.frameRate; screenShareCaptureOptions!.resolution!.aspectRatio = $event.aspectRatio">
</app-video-resolution>
</div>
}
@if (shareScreen) {
<mat-divider></mat-divider>
}
@if (shareScreen) {
<div>
<label><a href="https://docs.livekit.io/client-sdk-js/interfaces/ScreenShareCaptureOptions.html" target="_blank">ScreenShareCaptureOptions</a></label><br>
<mat-radio-group [(ngModel)]="screenOption" (change)="screenOptionChanged($event)">
<mat-radio-button [value]="true">True (default)</mat-radio-button>
@if (allowDisablingScreen) {
<mat-radio-button [value]="false">False (no screen)</mat-radio-button>
}
<mat-radio-button [value]="'custom'">Custom</mat-radio-button>
</mat-radio-group>
@if (screenOption == 'custom') {
<div>
<mat-checkbox id="screenShare-video" [(ngModel)]="screenShareCaptureOptions!.video">video</mat-checkbox>
<mat-checkbox id="screenShare-audio" [(ngModel)]="screenShareCaptureOptions!.audio">audio</mat-checkbox>
<mat-checkbox id="screenShare-preferCurrentTab" [(ngModel)]="screenShareCaptureOptions!.preferCurrentTab">preferCurrentTab</mat-checkbox>
<mat-checkbox id="screenShare-suppressLocalAudioPlayback" [(ngModel)]="screenShareCaptureOptions!.suppressLocalAudioPlayback">suppressLocalAudioPlayback</mat-checkbox>
@if (screenShareCaptureOptions!.video) {
<mat-form-field id="screenShare-displaySurface">
<mat-label>displaySurface</mat-label>
<mat-select [(value)]="auxScreenDisplaySurface">
@for (surface of ['NONE','window','browser','monitor']; track surface) {
<mat-option [value]="surface">{{surface}}</mat-option>
}
</mat-select>
</mat-form-field>
}
<mat-form-field id="screenShare-contentHint">
<mat-label>contentHint</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.contentHint">
@for (hint of ['text','detail','motion']; track hint) {
<mat-option [value]="hint">{{hint}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-selfBrowserSurface">
<mat-label>selfBrowserSurface</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.selfBrowserSurface">
@for (surface of ['include','exclude']; track surface) {
<mat-option [value]="surface">{{surface}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-surfaceSwitching">
<mat-label>surfaceSwitching</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.surfaceSwitching">
@for (surface of ['include','exclude']; track surface) {
<mat-option [value]="surface">{{surface}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field id="screenShare-systemAudio">
<mat-label>systemAudio</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.systemAudio">
@for (audio of ['include','exclude']; track audio) {
<mat-option [value]="audio">{{audio}}</mat-option>
}
</mat-select>
</mat-form-field>
<div>
<label>Resolution</label>
<mat-radio-group [(ngModel)]="customScreenShareResolution" (change)="handleCustomScreenResolutionChange()">
<mat-radio-button [value]="false">Default</mat-radio-button>
<mat-radio-button [value]="true">Custom</mat-radio-button>
</mat-radio-group>
@if (customScreenShareResolution) {
<app-video-resolution
[componentId]="'resolution-screen-capture-options'"
[showTitle]="false"
[width]="screenShareCaptureOptions!.resolution!.width"
[height]="screenShareCaptureOptions!.resolution!.height"
[frameRate]="screenShareCaptureOptions!.resolution!.frameRate"
[aspectRatio]="screenShareCaptureOptions!.resolution!.aspectRatio"
(resolutionChanged)="screenShareCaptureOptions!.resolution!.width = $event.width; screenShareCaptureOptions!.resolution!.height = $event.height; screenShareCaptureOptions!.resolution!.frameRate = $event.frameRate; screenShareCaptureOptions!.resolution!.aspectRatio = $event.aspectRatio">
</app-video-resolution>
}
</div>
</div>
}
</div>
</div>
<mat-divider *ngIf="trackPublishOptions"></mat-divider>
<div *ngIf="trackPublishOptions">
<label><a href="https://docs.livekit.io/client-sdk-js/interfaces/TrackPublishOptions.html" target="_blank">TrackPublishOptions</a></label><br>
<mat-checkbox id="trackPublish-simulcast" [(ngModel)]="trackPublishOptions.simulcast">simulcast</mat-checkbox>
<mat-checkbox id="trackPublish-dtx" [(ngModel)]="trackPublishOptions.dtx">dtx</mat-checkbox>
<mat-checkbox id="trackPublish-red" [(ngModel)]="trackPublishOptions.red">red</mat-checkbox>
<mat-checkbox id="trackPublish-backupCodec" [(ngModel)]="trackPublishOptions.backupCodec">backupCodec</mat-checkbox>
<mat-checkbox id="trackPublish-forceStereo" [(ngModel)]="trackPublishOptions.forceStereo">forceStereo</mat-checkbox>
<mat-checkbox id="trackPublish-stopMicTrackOnMute" [(ngModel)]="trackPublishOptions.stopMicTrackOnMute">stopMicTrackOnMute</mat-checkbox>
<mat-form-field id="trackPublish-videoCodec">
<mat-label>videoCodec</mat-label>
<mat-select [(value)]="trackPublishOptions.videoCodec">
<mat-option *ngFor="let codec of ['vp8','h264','vp9','av1']" [value]="codec" [id]="'mat-option-' + codec">{{codec | uppercase}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="trackPublish-scalabilityMode">
<mat-label>scalabilityMode</mat-label>
<mat-select [(value)]="trackPublishOptions.scalabilityMode">
<mat-option *ngFor="let mode of ['L1T1','L1T2','L1T3','L2T1','L2T1h','L2T1_KEY','L2T2','L2T2h','L2T2_KEY','L2T3','L2T3h','L2T3_KEY','L3T1','L3T1h','L3T1_KEY','L3T2','L3T2h','L3T2_KEY','L3T3','L3T3h','L3T3_KEY']"
[value]="mode" [ngClass]="'mode-' + mode">{{mode}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="inner-text">
<mat-label>name</mat-label>
<input matInput id="trackPublish-name" placeholder="name" [(ngModel)]="trackPublishOptions.name"/>
</mat-form-field>
<mat-form-field id="trackPublish-source">
<mat-label>source</mat-label>
<mat-select [(value)]="trackPublishOptions.source">
<mat-option *ngFor="let source of ENUMERATION_SOURCE" [value]="source">{{source}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field id="trackPublish-stream">
<mat-label>stream</mat-label>
<input matInput id="trackPublish-stream" placeholder="stream" [(ngModel)]="trackPublishOptions.stream"/>
</mat-form-field>
</div>
}
@if (trackPublishOptions) {
<mat-divider></mat-divider>
}
@if (trackPublishOptions) {
<div>
<label><a href="https://docs.livekit.io/client-sdk-js/interfaces/TrackPublishOptions.html" target="_blank">TrackPublishOptions</a></label><br>
<mat-checkbox id="trackPublish-simulcast" [(ngModel)]="trackPublishOptions.simulcast">simulcast</mat-checkbox>
<mat-checkbox id="trackPublish-dtx" [(ngModel)]="trackPublishOptions.dtx">dtx</mat-checkbox>
<mat-checkbox id="trackPublish-red" [(ngModel)]="trackPublishOptions.red">red</mat-checkbox>
<mat-checkbox id="trackPublish-backupCodec" [(ngModel)]="trackPublishOptions.backupCodec">backupCodec</mat-checkbox>
<mat-checkbox id="trackPublish-forceStereo" [(ngModel)]="trackPublishOptions.forceStereo">forceStereo</mat-checkbox>
<mat-checkbox id="trackPublish-stopMicTrackOnMute" [(ngModel)]="trackPublishOptions.stopMicTrackOnMute">stopMicTrackOnMute</mat-checkbox>
<mat-form-field id="trackPublish-videoCodec">
<mat-label>videoCodec</mat-label>
<mat-select [(value)]="trackPublishOptions.videoCodec">
@for (codec of ['vp8','h264','vp9','av1']; track codec) {
<mat-option [value]="codec" [id]="'mat-option-' + codec">{{codec | uppercase}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field id="trackPublish-scalabilityMode">
<mat-label>scalabilityMode</mat-label>
<mat-select [(value)]="trackPublishOptions.scalabilityMode">
@for (mode of ['L1T1','L1T2','L1T3','L2T1','L2T1h','L2T1_KEY','L2T2','L2T2h','L2T2_KEY','L2T3','L2T3h','L2T3_KEY','L3T1','L3T1h','L3T1_KEY','L3T2','L3T2h','L3T2_KEY','L3T3','L3T3h','L3T3_KEY']; track mode) {
<mat-option
[value]="mode" [ngClass]="'mode-' + mode">{{mode}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="inner-text">
<mat-label>name</mat-label>
<input matInput id="trackPublish-name" placeholder="name" [(ngModel)]="trackPublishOptions.name"/>
</mat-form-field>
<mat-form-field id="trackPublish-source">
<mat-label>source</mat-label>
<mat-select [(value)]="trackPublishOptions.source">
@for (source of ENUMERATION_SOURCE; track source) {
<mat-option [value]="source">{{source}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field id="trackPublish-stream">
<mat-label>stream</mat-label>
<input matInput id="trackPublish-stream" placeholder="stream" [(ngModel)]="trackPublishOptions.stream"/>
</mat-form-field>
</div>
}
</mat-dialog-content>
<mat-dialog-actions>

View File

@ -1,19 +1,21 @@
<div class="resolution-div">
<p *ngIf="showTitle" class="resolution-title">Resolution</p>
<mat-form-field class="inner-text-input">
<mat-label>width</mat-label>
<input matInput [id]="componentId+'-width'" type="number" placeholder="width" [(ngModel)]="width" (ngModelChange)="emitChanges()"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>height</mat-label>
<input matInput [id]="componentId+'-height'" type="number" placeholder="height" [(ngModel)]="height" (ngModelChange)="emitChanges()"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>frameRate</mat-label>
<input matInput [id]="componentId+'-frameRate'" type="number" placeholder="frameRate" [(ngModel)]="frameRate" (ngModelChange)="emitChanges()"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>aspectRatio</mat-label>
<input matInput [id]="componentId+'-aspectRatio'" type="number" placeholder="aspectRatio" [(ngModel)]="aspectRatio" (ngModelChange)="emitChanges()"/>
</mat-form-field>
@if (showTitle) {
<p class="resolution-title">Resolution</p>
}
<mat-form-field class="inner-text-input">
<mat-label>width</mat-label>
<input matInput [id]="componentId+'-width'" type="number" placeholder="width" [(ngModel)]="width" (ngModelChange)="emitChanges()"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>height</mat-label>
<input matInput [id]="componentId+'-height'" type="number" placeholder="height" [(ngModel)]="height" (ngModelChange)="emitChanges()"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>frameRate</mat-label>
<input matInput [id]="componentId+'-frameRate'" type="number" placeholder="frameRate" [(ngModel)]="frameRate" (ngModelChange)="emitChanges()"/>
</mat-form-field>
<mat-form-field class="inner-text-input">
<mat-label>aspectRatio</mat-label>
<input matInput [id]="componentId+'-aspectRatio'" type="number" placeholder="aspectRatio" [(ngModel)]="aspectRatio" (ngModelChange)="emitChanges()"/>
</mat-form-field>
</div>

View File

@ -25,30 +25,30 @@
<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="delete-room-api-btn" (click)="deleteRoom()" [disabled]="!apiRoomName">Delete
Room</button>
Room</button>
</span>
<span style="display: inline-block" matTooltip='"Room" required' [matTooltipDisabled]="!!apiRoomName">
<button mat-button id="list-participants-api-btn" (click)="listParticipants()" [disabled]="!apiRoomName">List
participants</button>
participants</button>
</span>
<span style="display: inline-block" matTooltip='"Room" and "Participant" required'
[matTooltipDisabled]="!!apiRoomName && !!apiParticipantIdentity">
<button mat-button id="get-participant-api-btn" (click)="getParticipant()"
[disabled]="!apiRoomName || !apiParticipantIdentity">Get participant</button>
[disabled]="!apiRoomName || !apiParticipantIdentity">Get participant</button>
</span>
<span style="display: inline-block" matTooltip='"Room" and "Participant" required'
[matTooltipDisabled]="!!apiRoomName && !!apiParticipantIdentity">
<button mat-button id="remove-participant-api-btn" (click)="removeParticipant()"
[disabled]="!apiRoomName || !apiParticipantIdentity">Remove participant</button>
[disabled]="!apiRoomName || !apiParticipantIdentity">Remove participant</button>
</span>
<span style="display: inline-block" matTooltip='"Room", "Participant" and "Track" required'
[matTooltipDisabled]="!!apiRoomName && !!apiParticipantIdentity && !!apiTrackSid">
<button mat-button id="force-unpublish-api-btn" (click)="mutePublishedTrack()"
[disabled]="!apiRoomName || !apiParticipantIdentity || !apiTrackSid">Mute
track</button>
track</button>
</span>
<mat-checkbox class="subscriber-checkbox" name="subscriber" [(ngModel)]="muteTrack"
[disabled]="!apiRoomName || !apiParticipantIdentity || !apiTrackSid">Mute</mat-checkbox>
[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>
@ -80,18 +80,18 @@
<button mat-button id="list-egress-api-btn" (click)="listEgress()">List Egress</button>
<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>
[disabled]="!egressRoomName">Start Room Composite Egress</button>
</span>
<span style="display: inline-block" matTooltip='"Room", "Audio Track" and "Video Track" required'
[matTooltipDisabled]="!(!egressRoomName || !audioTrackId || !videoTrackId)">
<button mat-button id="start-track-composite-egress-api-btn" (click)="startTrackCompositeEgress()"
[disabled]="!egressRoomName || !audioTrackId || !videoTrackId">Start Track Composite Egress</button>
[disabled]="!egressRoomName || !audioTrackId || !videoTrackId">Start Track Composite Egress</button>
</span>
<span style="display: inline-block" matTooltip='"Room" and only one of "Audio Track" or "Video Track" required'
[matTooltipDisabled]="!(!egressRoomName || (!!audioTrackId && !!videoTrackId || !audioTrackId && !videoTrackId))">
<button mat-button id="start-track-egress-api-btn" (click)="startTrackEgress()"
[disabled]="!egressRoomName || (!!audioTrackId && !!videoTrackId || !audioTrackId && !videoTrackId)">Start
Track Egress</button>
Track Egress</button>
</span>
<span style="display: inline-block" matTooltip='"Egress ID" required' [matTooltipDisabled]="!!egressId">
<button mat-button id="stop-egress-api-btn" (click)="stopEgress()" [disabled]="!egressId">Stop Egress</button>
@ -103,9 +103,11 @@
<mat-form-field id="room-composite-layout-select">
<mat-label>Layout</mat-label>
<mat-select [(value)]="roomCompositeLayoutSelected">
<mat-option *ngFor="let layout of ROOM_COMPOSITE_LAYOUTS" [value]="layout">
{{layout}}
</mat-option>
@for (layout of ROOM_COMPOSITE_LAYOUTS; track layout) {
<mat-option [value]="layout">
{{layout}}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox id="room-composite-audio-only" [(ngModel)]="roomCompositeAudioOnly">Audio only</mat-checkbox>
@ -116,34 +118,42 @@
<div class="egress-output">
<div class="egress-output-container">
<mat-checkbox id="file-output-checkbox" [(ngModel)]="fileOutputSelected">MP4 file output</mat-checkbox>
<mat-form-field id="s3-endpoint" *ngIf="fileOutputSelected">
<mat-label>S3 endpoint</mat-label>
<input matInput type="url" placeholder="S3 endpoint" [(ngModel)]="s3Endpoint">
</mat-form-field>
@if (fileOutputSelected) {
<mat-form-field id="s3-endpoint">
<mat-label>S3 endpoint</mat-label>
<input matInput type="url" placeholder="S3 endpoint" [(ngModel)]="s3Endpoint">
</mat-form-field>
}
</div>
<div class="egress-output-container">
<mat-checkbox id="stream-output-checkbox" [(ngModel)]="streamOutputSelected">RTMP stream output</mat-checkbox>
<mat-form-field *ngIf="streamOutputSelected" id="rmpt-urls" class="example-chip-list">
<mat-label>RTMP urls</mat-label>
<mat-chip-grid #chipGrid aria-label="Enter fruits">
<mat-chip-row *ngFor="let url of rtmpUrls" (removed)="removeRtmpUrl(url)">
{{url}}
<button class="remove-element-btn" matChipRemove aria-label="Remove URL">
<mat-icon class="remove-element-icon">cancel</mat-icon>
</button>
</mat-chip-row>
<input placeholder="New URL" [matChipInputFor]="chipGrid"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="addRtmpUrl($event)" />
</mat-chip-grid>
</mat-form-field>
@if (streamOutputSelected) {
<mat-form-field id="rmpt-urls" class="example-chip-list">
<mat-label>RTMP urls</mat-label>
<mat-chip-grid #chipGrid aria-label="Enter fruits">
@for (url of rtmpUrls; track url) {
<mat-chip-row (removed)="removeRtmpUrl(url)">
{{url}}
<button class="remove-element-btn" matChipRemove aria-label="Remove URL">
<mat-icon class="remove-element-icon">cancel</mat-icon>
</button>
</mat-chip-row>
}
<input placeholder="New URL" [matChipInputFor]="chipGrid"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="addRtmpUrl($event)" />
</mat-chip-grid>
</mat-form-field>
}
</div>
<div class="egress-output-container">
<mat-checkbox id="segment-output-checkbox" [(ngModel)]="segmentOutputSelected">HLS segment output</mat-checkbox>
<mat-form-field id="segment-duration" *ngIf="segmentOutputSelected">
<mat-label>Segment duration (s)</mat-label>
<input matInput type="number" min="1" placeholder="Segment duration" [(ngModel)]="segmentDuration">
</mat-form-field>
@if (segmentOutputSelected) {
<mat-form-field id="segment-duration">
<mat-label>Segment duration (s)</mat-label>
<input matInput type="number" min="1" placeholder="Segment duration" [(ngModel)]="segmentDuration">
</mat-form-field>
}
</div>
</div>
@ -166,18 +176,20 @@
<span style="display: inline-block" [matTooltip]="!ingressRoomName ? 'Room required' : 'At least one of audio and video required'"
[matTooltipDisabled]="!!ingressRoomName && (ingressWithAudio || ingressWithVideo)">
<button mat-button id="create-ingress-api-btn" (click)="createIngress()"
[disabled]="!ingressRoomName || (!ingressWithAudio && !ingressWithVideo)">Create Ingress</button>
[disabled]="!ingressRoomName || (!ingressWithAudio && !ingressWithVideo)">Create Ingress</button>
</span>
<span style="display: inline-block" matTooltip='"Ingress ID" required' [matTooltipDisabled]="!!ingressId">
<button mat-button id="delete-ingress-api-btn" (click)="deleteIngress()" [disabled]="!ingressId">Delete
Ingress</button>
Ingress</button>
</span>
<mat-form-field id="ingress-input-type-select">
<mat-label>Input Type</mat-label>
<mat-select [(value)]="inputTypeSelected">
<mat-option *ngFor="let inputType of INGRESS_INPUT_TYPES" [value]="inputType.value">
{{inputType.viewValue}}
</mat-option>
@for (inputType of INGRESS_INPUT_TYPES; track inputType) {
<mat-option [value]="inputType.value">
{{inputType.viewValue}}
</mat-option>
}
</mat-select>
</mat-form-field>
<span style="display: inline-block">
@ -192,7 +204,7 @@
<span style="display: inline-block" [matTooltip]="!ingressWithVideo ? 'Only with video' : 'Preset overrides this value'"
[matTooltipDisabled]="!!ingressWithVideo && ingressVideoEncodingPresetSelected == undefined">
<mat-checkbox id="ingress-simulcast" [(ngModel)]="ingressSimulcast"
[disabled]="!ingressWithVideo || ingressVideoEncodingPresetSelected != undefined">Simulcast</mat-checkbox>
[disabled]="!ingressWithVideo || ingressVideoEncodingPresetSelected != undefined">Simulcast</mat-checkbox>
</span>
<span style="display: inline-block" matTooltip="Only for WHIP" [matTooltipDisabled]="inputTypeSelected === 1">
<mat-checkbox id="ingress-transcoding" [(ngModel)]="ingressEnableTranscoding" [disabled]="inputTypeSelected !== 1">Transcoding</mat-checkbox>
@ -201,9 +213,11 @@
<mat-form-field id="ingress-url-type-select">
<mat-label>URL type</mat-label>
<mat-select [(value)]="ingressUrlType" [disabled]="inputTypeSelected !== 2">
<mat-option *ngFor="let urlType of INGRESS_URL_TYPES" [value]="urlType" [id]="'mat-option-' + urlType">
{{urlType}}
</mat-option>
@for (urlType of INGRESS_URL_TYPES; track urlType) {
<mat-option [value]="urlType" [id]="'mat-option-' + urlType">
{{urlType}}
</mat-option>
}
</mat-select>
</mat-form-field>
</span>
@ -212,9 +226,11 @@
<mat-form-field id="ingress-video-codec-select">
<mat-label>Codec</mat-label>
<mat-select [(value)]="ingressVideoCodecSelected" [disabled]="!ingressWithVideo || ingressVideoEncodingPresetSelected != undefined">
<mat-option *ngFor="let codec of INGRESS_VIDEO_CODECS" [value]="codec.value" [id]="'mat-option-' + codec.viewValue">
{{codec.viewValue}}
</mat-option>
@for (codec of INGRESS_VIDEO_CODECS; track codec) {
<mat-option [value]="codec.value" [id]="'mat-option-' + codec.viewValue">
{{codec.viewValue}}
</mat-option>
}
</mat-select>
</mat-form-field>
</span>
@ -222,9 +238,11 @@
<mat-form-field id="ingress-preset-select">
<mat-label>Preset</mat-label>
<mat-select [(value)]="ingressVideoEncodingPresetSelected" [disabled]="!ingressWithVideo">
<mat-option *ngFor="let preset of INGRESS_VIDEO_ENCODING_PRESETS" [value]="preset.value" [id]="'mat-option-' + preset.viewValue">
{{preset.viewValue}}
</mat-option>
@for (preset of INGRESS_VIDEO_ENCODING_PRESETS; track preset) {
<mat-option [value]="preset.value" [id]="'mat-option-' + preset.viewValue">
{{preset.viewValue}}
</mat-option>
}
</mat-select>
</mat-form-field>
</span>

View File

@ -1,99 +1,100 @@
<div class="div-wrapper">
<div class="config-half">
<mat-card class="config-card">
<div class="config-half">
<mat-card class="config-card">
<mat-card-content>
<div class="row no-wrap-row">
<mat-card-content>
<div class="row no-wrap-row">
<mat-form-field style="margin-right: 8px" class="custom-mat-form-field">
<mat-label>Room</mat-label>
<input matInput placeholder="Room name" [id]="'room-name-input-' + index" [(ngModel)]="roomName"
[disabled]="!!room">
</mat-form-field>
<mat-form-field style="margin-right: 8px" class="custom-mat-form-field">
<mat-label>Room</mat-label>
<input matInput placeholder="Room name" [id]="'room-name-input-' + index" [(ngModel)]="roomName"
[disabled]="!!room">
</mat-form-field>
<mat-form-field class="custom-mat-form-field">
<mat-label>Participant</mat-label>
<input matInput placeholder="Participant name" [id]="'participant-name-input-'+ index"
[(ngModel)]="participantName" [disabled]="!!room">
</mat-form-field>
<mat-form-field class="custom-mat-form-field">
<mat-label>Participant</mat-label>
<input matInput placeholder="Participant name" [id]="'participant-name-input-'+ index"
[(ngModel)]="participantName" [disabled]="!!room">
</mat-form-field>
<div class="room-btns-div">
<button mat-icon-button title="Room options" [id]="'room-options-btn-' + index"
class="mat-icon-custom" (click)="openOptionsDialog()" [disabled]="room">
<mat-icon class="mat-icon-custom-ic" aria-label="Room options button">settings</mat-icon>
</button>
<button mat-icon-button title="Room API" [id]="'room-api-btn-' + index" class="mat-icon-custom"
(click)="openRoomApiDialog()">
<mat-icon class="mat-icon-custom-ic" aria-label="Room API button">cloud_circle</mat-icon>
</button>
<button mat-icon-button title="Room events" [id]="'room-events-btn-' + index"
class="mat-icon-custom" (click)="openRoomEventsDialog()">
<mat-icon class="mat-icon-custom-ic"
aria-label="Room events button">notifications</mat-icon>
</button>
</div>
<div class="room-btns-div">
<button mat-icon-button title="Room options" [id]="'room-options-btn-' + index"
class="mat-icon-custom" (click)="openOptionsDialog()" [disabled]="room">
<mat-icon class="mat-icon-custom-ic" aria-label="Room options button">settings</mat-icon>
</button>
<button mat-icon-button title="Room API" [id]="'room-api-btn-' + index" class="mat-icon-custom"
(click)="openRoomApiDialog()">
<mat-icon class="mat-icon-custom-ic" aria-label="Room API button">cloud_circle</mat-icon>
</button>
<button mat-icon-button title="Room events" [id]="'room-events-btn-' + index"
class="mat-icon-custom" (click)="openRoomEventsDialog()">
<mat-icon class="mat-icon-custom-ic"
aria-label="Room events button">notifications</mat-icon>
</button>
</div>
</div>
</div>
<div class="row no-wrap-row">
<button class="connect-btn" mat-button (click)="createTokenAndConnectRoom()"
[disabled]="!!room">CONNECT</button>
<mat-checkbox class="subscriber-checkbox" name="subscriber" [(ngModel)]="roomConf.subscriber"
[disabled]="!!room">Subscriber</mat-checkbox>
<mat-checkbox class="publisher-checkbox" name="publisher" [(ngModel)]="roomConf.publisher"
[disabled]="!!room">Publisher</mat-checkbox>
</div>
</mat-card-content>
</mat-card>
</div>
<div *ngIf="room" class="room-half">
<mat-card class="room-card">
<mat-card-header style="margin-bottom: 7px">
<div class="row">
<mat-card-title class="room-mat-card-title">{{room.name}}</mat-card-title>
<div class="room-actions">
<button class="peer-info-btn" (click)="openInfoDialog()" title="PCTransports info">
<mat-icon aria-label="PCTransports info button">info</mat-icon>
</button>
<button class="message-btn" (click)="sendData()" title="Broadcast message to room">
<mat-icon aria-label="Send message button">chat</mat-icon>
</button>
<button class="disconnect-btn" (click)="disconnectRoom()" title="Disconnect room">
<mat-icon aria-label="Disconnect button">clear</mat-icon>
</button>
</div>
</div>
</mat-card-header>
<mat-card-content class="room-card-content">
<div class="event-list-flex">
<div class="event-list scroll-custom">
<mat-accordion [attr.id]="'room-events-' + room.localParticipant.identity">
<mat-expansion-panel *ngFor="let event of events" [ngClass]="event.eventCategory">
<mat-expansion-panel-header
[ngClass]="event.eventType + '-' + room.localParticipant.identity"
[collapsedHeight]="'20px'" [expandedHeight]="'20px'">
{{event.eventType}}
</mat-expansion-panel-header>
<div class="event-content">{{event.eventDescription}}</div>
</mat-expansion-panel>
</mat-accordion>
</div>
</div>
<div>
<app-participant class="local-participant" [participant]="room.localParticipant" [room]="room"
[index]="index"></app-participant>
<app-participant class="remote-participant" *ngFor="let participant of room.remoteParticipants | keyvalue"
[participant]="participant.value" [room]="room" [index]="index" (sendDataToOneParticipant)="sendData($event)"></app-participant>
</div>
</mat-card-content>
</mat-card>
<div class="row no-wrap-row">
<button class="connect-btn" mat-button (click)="createTokenAndConnectRoom()"
[disabled]="!!room">CONNECT</button>
<mat-checkbox class="subscriber-checkbox" name="subscriber" [(ngModel)]="roomConf.subscriber"
[disabled]="!!room">Subscriber</mat-checkbox>
<mat-checkbox class="publisher-checkbox" name="publisher" [(ngModel)]="roomConf.publisher"
[disabled]="!!room">Publisher</mat-checkbox>
</div>
</mat-card-content>
</mat-card>
</div>
@if (room) {
<div class="room-half">
<mat-card class="room-card">
<mat-card-header style="margin-bottom: 7px">
<div class="row">
<mat-card-title class="room-mat-card-title">{{room.name}}</mat-card-title>
<div class="room-actions">
<button class="peer-info-btn" (click)="openInfoDialog()" title="PCTransports info">
<mat-icon aria-label="PCTransports info button">info</mat-icon>
</button>
<button class="message-btn" (click)="sendData()" title="Broadcast message to room">
<mat-icon aria-label="Send message button">chat</mat-icon>
</button>
<button class="disconnect-btn" (click)="disconnectRoom()" title="Disconnect room">
<mat-icon aria-label="Disconnect button">clear</mat-icon>
</button>
</div>
</div>
</mat-card-header>
<mat-card-content class="room-card-content">
<div class="event-list-flex">
<div class="event-list scroll-custom">
<mat-accordion [attr.id]="'room-events-' + room.localParticipant.identity">
@for (event of events; track event) {
<mat-expansion-panel [ngClass]="event.eventCategory">
<mat-expansion-panel-header
[ngClass]="event.eventType + '-' + room.localParticipant.identity"
[collapsedHeight]="'20px'" [expandedHeight]="'20px'">
{{event.eventType}}
</mat-expansion-panel-header>
<div class="event-content">{{event.eventDescription}}</div>
</mat-expansion-panel>
}
</mat-accordion>
</div>
</div>
<div>
<app-participant class="local-participant" [participant]="room.localParticipant" [room]="room"
[index]="index"></app-participant>
@for (participant of room.remoteParticipants | keyvalue; track participant) {
<app-participant class="remote-participant"
[participant]="participant.value" [room]="room" [index]="index" (sendDataToOneParticipant)="sendData($event)"></app-participant>
}
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>

View File

@ -1,61 +1,85 @@
<div class="participant-container">
<div class="participant-actions">
<p class="participant-identity" [ngClass]="{'local-participant-identity' : participant.isLocal}">
{{participant.identity}}</p>
<div class="participant-buttons">
<button *ngIf="participant.isLocal" class="add-audio-btn" (click)="addAudioTrack()" title="New audio track"
matTooltip="New audio track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New audio track">microphone</mat-icon>
</button>
<button *ngIf="participant.isLocal" class="options-audio-btn" (click)="openAudioTrackOptionsDialog()"
title="Video track options" matTooltip="Audio track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Audio options">more_vert</mat-icon>
</button>
<button *ngIf="participant.isLocal" class="add-video-btn" (click)="addVideoTrack()" title="New video track"
matTooltip="New video track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New video track">videocam</mat-icon>
</button>
<button *ngIf="participant.isLocal" class="options-video-btn" (click)="openVideoTrackOptionsDialog()"
title="Video track options" matTooltip="Video track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Video options">more_vert</mat-icon>
</button>
<button *ngIf="participant.isLocal" class="add-screen-btn" (click)="addScreenTrack()"
title="New screen track" matTooltip="New screen track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New screen track">present_to_all</mat-icon>
</button>
<button *ngIf="participant.isLocal" class="options-screen-btn" (click)="openScreenTrackOptionsDialog()"
title="Screen track options" matTooltip="Screen track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Screen options">more_vert</mat-icon>
</button>
<button *ngIf="participant.isLocal" class="options-track-publish-btn" (click)="openTrackPublishOptionsDialog()"
title="Track publish options" matTooltip="Track publish options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Track publish options">settings</mat-icon>
</button>
<button *ngIf="!participant.isLocal" class="message-btn" (click)="sendData()" title="Send message to this participant">
<mat-icon aria-label="Send message button">chat</mat-icon>
</button>
</div>
<div class="participant-actions">
<p class="participant-identity" [ngClass]="{'local-participant-identity' : participant.isLocal}">
{{participant.identity}}</p>
<div class="participant-buttons">
@if (participant.isLocal) {
<button class="add-audio-btn" (click)="addAudioTrack()" title="New audio track"
matTooltip="New audio track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New audio track">microphone</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="options-audio-btn" (click)="openAudioTrackOptionsDialog()"
title="Video track options" matTooltip="Audio track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Audio options">more_vert</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="add-video-btn" (click)="addVideoTrack()" title="New video track"
matTooltip="New video track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New video track">videocam</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="options-video-btn" (click)="openVideoTrackOptionsDialog()"
title="Video track options" matTooltip="Video track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Video options">more_vert</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="add-screen-btn" (click)="addScreenTrack()"
title="New screen track" matTooltip="New screen track" matTooltipClass="custom-tooltip">
<mat-icon aria-label="New screen track">present_to_all</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="options-screen-btn" (click)="openScreenTrackOptionsDialog()"
title="Screen track options" matTooltip="Screen track options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Screen options">more_vert</mat-icon>
</button>
}
@if (participant.isLocal) {
<button class="options-track-publish-btn" (click)="openTrackPublishOptionsDialog()"
title="Track publish options" matTooltip="Track publish options" matTooltipClass="custom-tooltip">
<mat-icon aria-label="Track publish options">settings</mat-icon>
</button>
}
@if (!participant.isLocal) {
<button class="message-btn" (click)="sendData()" title="Send message to this participant">
<mat-icon aria-label="Send message button">chat</mat-icon>
</button>
}
</div>
<div *ngIf="participant" class="participant-content">
<div class="event-list scroll-custom">
<mat-accordion [attr.id]="index + '-participant-events-' + participant.identity">
<mat-expansion-panel *ngFor="let event of events"
[ngClass]="event.eventCategory">
<mat-expansion-panel-header [ngClass]="event.eventType + '-' + participant.identity"
[collapsedHeight]="'20px'" [expandedHeight]="'20px'">
{{event.eventType}}
</mat-expansion-panel-header>
<div class="event-content">{{event.eventDescription}}</div>
</mat-expansion-panel>
</mat-accordion>
</div>
<div class="audio-tracks-container">
<app-audio-track *ngFor="let trackPublication of participant.audioTrackPublications| keyvalue"
[index]="index" [trackPublication]="trackPublication.value" [track]="trackPublication.value.audioTrack"
[localParticipant]="localParticipant" (newTrackEvent)="events.push($event)"></app-audio-track>
</div>
<app-video-track *ngFor="let trackPublication of participant.videoTrackPublications | keyvalue"
[index]="index" [trackPublication]="trackPublication.value" [track]="trackPublication.value.videoTrack"
[localParticipant]="localParticipant" (newTrackEvent)="events.push($event)"></app-video-track>
</div>
@if (participant) {
<div class="participant-content">
<div class="event-list scroll-custom">
<mat-accordion [attr.id]="index + '-participant-events-' + participant.identity">
@for (event of events; track event) {
<mat-expansion-panel
[ngClass]="event.eventCategory">
<mat-expansion-panel-header [ngClass]="event.eventType + '-' + participant.identity"
[collapsedHeight]="'20px'" [expandedHeight]="'20px'">
{{event.eventType}}
</mat-expansion-panel-header>
<div class="event-content">{{event.eventDescription}}</div>
</mat-expansion-panel>
}
</mat-accordion>
</div>
<div class="audio-tracks-container">
@for (trackPublication of participant.audioTrackPublications| keyvalue; track trackPublication) {
<app-audio-track
[index]="index" [trackPublication]="trackPublication.value" [track]="trackPublication.value.audioTrack"
[localParticipant]="localParticipant" (newTrackEvent)="events.push($event)"></app-audio-track>
}
</div>
@for (trackPublication of participant.videoTrackPublications | keyvalue; track trackPublication) {
<app-video-track
[index]="index" [trackPublication]="trackPublication.value" [track]="trackPublication.value.videoTrack"
[localParticipant]="localParticipant" (newTrackEvent)="events.push($event)"></app-video-track>
}
</div>
}
</div>

View File

@ -14,12 +14,14 @@
</div>
<div>
<button mat-icon-button id="scenario-options-btn" title="Scenario options" class="mat-icon-custom" (click)="openScenarioOptionsDialog()" [disabled]="scenarioPlaying">
<mat-icon class="mat-icon-custom-ic" aria-label="Room options button">settings</mat-icon>
<mat-icon class="mat-icon-custom-ic" aria-label="Room options button">settings</mat-icon>
</button>
<button id="finish-btn" mat-raised-button color="primary" (click)="endScenario()" [disabled]="!scenarioPlaying">FINISH</button>
</div>
</div>
<div class="instance-div">
<app-users-table *ngIf="!!users.length" [users]="users"></app-users-table>
@if (!!users.length) {
<app-users-table [users]="users"></app-users-table>
}
</div>

View File

@ -1,29 +1,31 @@
<div>
<div class="top-div">
<div class="controls-div">
<button id="add-user-btn" mat-raised-button color="primary" (click)="addUser()">ADD USER</button>
<button id="remove-user-btn" mat-raised-button color="primary" (click)="removeUser()"
[disabled]="!users.length">REMOVE
USER</button>
<button id="remove-all-users-btn" mat-raised-button color="primary" (click)="removeAllUsers()"
[disabled]="!users.length">REMOVE
ALL</button>
</div>
<div class="scenario-div">
<mat-checkbox id="auto-join-checkbox" class="auto-join-check" [(ngModel)]="autoJoin" name="autoJoin">Auto
join</mat-checkbox>
<button id="one2one-btn" mat-raised-button color="primary" (click)="loadScenario(numberParticipants,0,0)">{{numberParticipants}}:{{numberParticipants}}</button>
<button id="one2many-btn" mat-raised-button color="primary"
(click)="loadScenario(0,1,numberParticipants)">1 PUB : {{numberParticipants}} SUB</button>
<mat-form-field>
<input id="one2many-input" matInput type="number" min=1 max=100 [(ngModel)]="numberParticipants">
</mat-form-field>
</div>
<div class="top-div">
<div class="controls-div">
<button id="add-user-btn" mat-raised-button color="primary" (click)="addUser()">ADD USER</button>
<button id="remove-user-btn" mat-raised-button color="primary" (click)="removeUser()"
[disabled]="!users.length">REMOVE
USER</button>
<button id="remove-all-users-btn" mat-raised-button color="primary" (click)="removeAllUsers()"
[disabled]="!users.length">REMOVE
ALL</button>
</div>
<div class="scenario-div">
<mat-checkbox id="auto-join-checkbox" class="auto-join-check" [(ngModel)]="autoJoin" name="autoJoin">Auto
join</mat-checkbox>
<button id="one2one-btn" mat-raised-button color="primary" (click)="loadScenario(numberParticipants,0,0)">{{numberParticipants}}:{{numberParticipants}}</button>
<button id="one2many-btn" mat-raised-button color="primary"
(click)="loadScenario(0,1,numberParticipants)">1 PUB : {{numberParticipants}} SUB</button>
<mat-form-field>
<input id="one2many-input" matInput type="number" min=1 max=100 [(ngModel)]="numberParticipants">
</mat-form-field>
</div>
</div>
<div class="instance-div">
<app-openvidu-instance @fadeAnimation *ngFor="let user of users; let i=index" [attr.id]="'openvidu-instance-' + i" [roomConf]="user" [index]="i">
</app-openvidu-instance>
</div>
<div class="instance-div">
@for (user of users; track user; let i = $index) {
<app-openvidu-instance @fadeAnimation [attr.id]="'openvidu-instance-' + i" [roomConf]="user" [index]="i">
</app-openvidu-instance>
}
</div>
</div>

View File

@ -1,28 +1,38 @@
<table class="mat-elevation-z8">
<tr class="mat-row">
<th class="mat-cell">
<p id="number-of-streams">STREAMS</p>
<p>
<span [matBadge]="numberOfStreamsOut()" matBadgeOverlap="false">OUT</span>
</p>
<p>
<span [matBadge]="numberOfStreamsIn()" matBadgeOverlap="false">IN</span>
</p>
</th>
<th *ngFor="let publisher of users | callback: filterPublishers" class="mat-cell">
<p>{{publisher.room.localParticipant.identity}}</p>
<app-table-video *ngIf="publisher.localTracks.audio || publisher.localTracks.video"
[tracks]="publisher.localTracks"
[videoId]="'pub-' + publisher.room.localParticipant.identity">
</app-table-video>
</th>
</tr>
<tr *ngFor="let subscriber of users | callback: filterSubscribers" class="mat-cell">
<td class="mat-cell">{{subscriber.room.localParticipant.identity}}</td>
<td *ngFor="let publisher of users | callback: filterPublishers" class="mat-cell">
<app-table-video *ngIf="subscriber.room.localParticipant.identity !== publisher.room.localParticipant.identity && getRemoteTracksForPublisher(subscriber, publisher) as remoteTracks"
[tracks]="remoteTracks" [videoId]="'sub-' + subscriber.room.localParticipant.identity + '-of-pub-' + publisher.room.localParticipant.identity">
<tr class="mat-row">
<th class="mat-cell">
<p id="number-of-streams">STREAMS</p>
<p>
<span [matBadge]="numberOfStreamsOut()" matBadgeOverlap="false">OUT</span>
</p>
<p>
<span [matBadge]="numberOfStreamsIn()" matBadgeOverlap="false">IN</span>
</p>
</th>
@for (publisher of users | callback: filterPublishers; track publisher) {
<th class="mat-cell">
<p>{{publisher.room.localParticipant.identity}}</p>
@if (publisher.localTracks.audio || publisher.localTracks.video) {
<app-table-video
[tracks]="publisher.localTracks"
[videoId]="'pub-' + publisher.room.localParticipant.identity">
</app-table-video>
}
</th>
}
</tr>
@for (subscriber of users | callback: filterSubscribers; track subscriber) {
<tr class="mat-cell">
<td class="mat-cell">{{subscriber.room.localParticipant.identity}}</td>
@for (publisher of users | callback: filterPublishers; track publisher) {
<td class="mat-cell">
@if (subscriber.room.localParticipant.identity !== publisher.room.localParticipant.identity && getRemoteTracksForPublisher(subscriber, publisher); as remoteTracks) {
<app-table-video
[tracks]="remoteTracks" [videoId]="'sub-' + subscriber.room.localParticipant.identity + '-of-pub-' + publisher.room.localParticipant.identity">
</app-table-video>
}
</td>
}
</tr>
}
</table>

View File

@ -1,46 +1,60 @@
<div class="parent-div">
<video #mediaElement [id]="finalElementRefId" [ngClass]="getTrackOrigin()"></video>
<div class="bottom-div">
<button *ngIf="localParticipant" (click)="muteUnmuteVideo()" class="video-btn mute-unmute-video" matTooltip="Mute/Unmute video"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Mute/Unmute video" class="mat-icon material-icons" role="img"
aria-hidden="true">{{muteVideoIcon}}</mat-icon>
</button>
<button *ngIf="localParticipant" (click)="unpublishTrack()" class="video-btn publish-unpublish-video" matTooltip="Unpublish track"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Unpublish track" class="mat-icon material-icons" role="img"
aria-hidden="true">stop</mat-icon>
</button>
<button *ngIf="!localParticipant" (click)="toggleEnableTrack()" class="video-btn toggle-video-enabled" matTooltip="Toggle track enabled"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Toggle track enabled" class="mat-icon material-icons" role="img"
aria-hidden="true">{{trackEnabled ? 'toggle_off' : 'toggle_on'}}</mat-icon>
</button>
<button *ngIf="!localParticipant" (click)="toggleSubscribeTrack()" class="video-btn toggle-video-subscribed" matTooltip="Toggle track subscription"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Toggle track subscription" class="mat-icon material-icons" role="img"
aria-hidden="true">{{trackSubscribed ? 'stop' : 'play_arrow'}}</mat-icon>
</button>
<mat-form-field *ngIf="!localParticipant" id="max-video-quality" class="video-btn quality-option" matTooltip="Set video quality" matTooltipClass="custom-tooltip">
<mat-select [(value)]="maxVideoQuality" (selectionChange)="onQualityChange()">
<mat-option *ngFor="let q of ['LOW', 'MEDIUM', 'HIGH']" [value]="q" [ngClass]="'mode-' + q">{{q}}</mat-option>
</mat-select>
</mat-form-field>
<button (click)="openInfoDialog()" class="video-btn video-track-info" matTooltip="Open info dialog"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Open info dialog" class="mat-icon material-icons" role="img"
aria-hidden="true">info</mat-icon>
</button>
<!--<button *ngIf="isLocal" (click)="blur()" class="video-btn">
<mat-icon aria-label="Blur video" class="mat-icon material-icons" role="img"
aria-hidden="true">{{blurIcon}}</mat-icon>
</button>-->
</div>
<div class="top-right-div">
<button *ngIf="!localParticipant" (click)="toggleVideoZoom()" class="video-btn toggle-video-zoom" matTooltip="Toggle video zoom"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Toggle video zoom" class="mat-icon material-icons" role="img"
aria-hidden="true">{{videoZoom ? 'zoom_out' : 'zoom_in'}}</mat-icon>
</button>
</div>
<video #mediaElement [id]="finalElementRefId" [ngClass]="getTrackOrigin()"></video>
<div class="bottom-div">
@if (localParticipant) {
<button (click)="muteUnmuteVideo()" class="video-btn mute-unmute-video" matTooltip="Mute/Unmute video"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Mute/Unmute video" class="mat-icon material-icons" role="img"
aria-hidden="true">{{muteVideoIcon}}</mat-icon>
</button>
}
@if (localParticipant) {
<button (click)="unpublishTrack()" class="video-btn publish-unpublish-video" matTooltip="Unpublish track"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Unpublish track" class="mat-icon material-icons" role="img"
aria-hidden="true">stop</mat-icon>
</button>
}
@if (!localParticipant) {
<button (click)="toggleEnableTrack()" class="video-btn toggle-video-enabled" matTooltip="Toggle track enabled"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Toggle track enabled" class="mat-icon material-icons" role="img"
aria-hidden="true">{{trackEnabled ? 'toggle_off' : 'toggle_on'}}</mat-icon>
</button>
}
@if (!localParticipant) {
<button (click)="toggleSubscribeTrack()" class="video-btn toggle-video-subscribed" matTooltip="Toggle track subscription"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Toggle track subscription" class="mat-icon material-icons" role="img"
aria-hidden="true">{{trackSubscribed ? 'stop' : 'play_arrow'}}</mat-icon>
</button>
}
@if (!localParticipant) {
<mat-form-field id="max-video-quality" class="video-btn quality-option" matTooltip="Set video quality" matTooltipClass="custom-tooltip">
<mat-select [(value)]="maxVideoQuality" (selectionChange)="onQualityChange()">
@for (q of ['LOW', 'MEDIUM', 'HIGH']; track q) {
<mat-option [value]="q" [ngClass]="'mode-' + q">{{q}}</mat-option>
}
</mat-select>
</mat-form-field>
}
<button (click)="openInfoDialog()" class="video-btn video-track-info" matTooltip="Open info dialog"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Open info dialog" class="mat-icon material-icons" role="img"
aria-hidden="true">info</mat-icon>
</button>
<!--<button *ngIf="isLocal" (click)="blur()" class="video-btn">
<mat-icon aria-label="Blur video" class="mat-icon material-icons" role="img"
aria-hidden="true">{{blurIcon}}</mat-icon>
</button>-->
</div>
<div class="top-right-div">
@if (!localParticipant) {
<button (click)="toggleVideoZoom()" class="video-btn toggle-video-zoom" matTooltip="Toggle video zoom"
matTooltipClass="custom-tooltip">
<mat-icon aria-label="Toggle video zoom" class="mat-icon material-icons" role="img"
aria-hidden="true">{{videoZoom ? 'zoom_out' : 'zoom_in'}}</mat-icon>
</button>
}
</div>
</div>

View File

@ -14,7 +14,7 @@
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"moduleResolution": "bundler",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
@ -25,7 +25,9 @@
"dom"
],
"paths": {
"crypto": ["./node_modules/crypto-browserify"],
"crypto": [
"./node_modules/crypto-browserify"
],
"stream": [
"node_modules/stream-browserify"
],