openvidu-testapp: complete participant options. Add VideoResolution

pull/845/head
pabloFuente 2024-09-17 14:46:21 +02:00
parent 7e7b6d2915
commit 888f0bdb7e
14 changed files with 421 additions and 145 deletions

View File

@ -44,6 +44,7 @@ import { UsersTableComponent } from './components/users-table/users-table.compon
import { TableVideoComponent } from './components/users-table/table-video.component';
import { CallbackPipe } from './pipes/callback.pipe';
import { AppRoutingModule } from './app.routing';
import { VideoResolutionComponent } from './components/dialogs/options-dialog/video-resolution/video-resolution.component';
@NgModule({
declarations: [
@ -61,6 +62,7 @@ import { AppRoutingModule } from './app.routing';
TableVideoComponent,
CallbackPipe,
OptionsDialogComponent,
VideoResolutionComponent,
],
imports: [
FormsModule,

View File

@ -1,6 +1,26 @@
mat-form-field {
margin-top: 10px;
margin-right: 5px;
margin: 10px 5px 0 5px;
font-size: 14px;
}
mat-form-field:first-child {
margin-left: 0;
}
mat-radio-group {
font-size: 14px;
}
mat-checkbox {
font-size: 14px;
}
mat-select {
font-size: 14px;
}
mat-option {
font-size: 14px;
}
a {

View File

@ -4,81 +4,72 @@
<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><br>
<mat-checkbox id="room-adaptiveStream" [(ngModel)]="roomOptions.adaptiveStream" [style.fontSize.px]="14">adaptiveStream</mat-checkbox>
<mat-checkbox id="room-dynacast" [(ngModel)]="roomOptions.dynacast" [style.fontSize.px]="14">dynacast</mat-checkbox>
<mat-checkbox id="room-disconnectOnPageLeave" [(ngModel)]="roomOptions.disconnectOnPageLeave" [style.fontSize.px]="14">disconnectOnPageLeave</mat-checkbox>
<mat-checkbox id="room-stopLocalTrackOnUnpublish" [(ngModel)]="roomOptions.stopLocalTrackOnUnpublish" [style.fontSize.px]="14">stopLocalTrackOnUnpublish</mat-checkbox>
<mat-checkbox id="room-webAudioMix" [(ngModel)]="roomOptions.webAudioMix" [style.fontSize.px]="14">webAudioMix</mat-checkbox>
<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>
</div>
<mat-divider *ngIf="createLocalTracksOptions"></mat-divider>
<div *ngIf="createLocalTracksOptions">
<label class="label">CreateLocalTracksOptions</label>
<div>
<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">True (default)</mat-radio-button>
<mat-radio-button [value]="false">False (no video)</mat-radio-button>
<mat-radio-button *ngIf="allowDisablingVideo" [value]="false">False (no video)</mat-radio-button>
<mat-radio-button [value]="'custom'">Custom</mat-radio-button>
</mat-radio-group>
<div *ngIf="videoOption === 'custom'">
<mat-form-field class="inner-text-input" [style.fontSize.px]="14">
<mat-form-field class="inner-text-input">
<mat-label>deviceId</mat-label>
<input matInput id="video-deviceId" placeholder="deviceId" [(ngModel)]="auxVideoCaptureOptions.deviceId"/>
</mat-form-field>
<mat-form-field id="video-facingMode" [style.fontSize.px]="14">
<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>
<mat-form-field class="inner-text-input" [style.fontSize.px]="14">
<mat-label>aspectRatio</mat-label>
<input matInput id="video-aspectRatio" placeholder="aspectRatio" [(ngModel)]="auxVideoCaptureOptions.resolution!.aspectRatio"/>
</mat-form-field>
<mat-form-field class="inner-text-input" [style.fontSize.px]="14">
<mat-label>frameRate</mat-label>
<input matInput id="video-frameRate" placeholder="frameRate" [(ngModel)]="auxVideoCaptureOptions.resolution!.frameRate"/>
</mat-form-field>
<mat-form-field class="inner-text-input" [style.fontSize.px]="14">
<mat-label>width</mat-label>
<input matInput id="video-width" placeholder="width" [(ngModel)]="auxVideoCaptureOptions.resolution!.width"/>
</mat-form-field>
<mat-form-field class="inner-text-input" [style.fontSize.px]="14">
<mat-label>height</mat-label>
<input matInput id="video-height" placeholder="height" [(ngModel)]="auxVideoCaptureOptions.resolution!.height"/>
</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>
<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">True (default)</mat-radio-button>
<mat-radio-button [value]="false">False (no audio)</mat-radio-button>
<mat-radio-button *ngIf="allowDisablingAudio" [value]="false">False (no audio)</mat-radio-button>
<mat-radio-button [value]="'custom'">Custom</mat-radio-button>
</mat-radio-group>
<div *ngIf="audioOption === 'custom'">
<div>
<mat-checkbox id="audio-autoGainControl" [(ngModel)]="auxAudioCaptureOptions.autoGainControl" [style.fontSize.px]="14">autoGainControl</mat-checkbox>
<mat-checkbox id="audio-echoCancellation" [(ngModel)]="auxAudioCaptureOptions.echoCancellation" [style.fontSize.px]="14">echoCancellation</mat-checkbox>
<mat-checkbox id="audio-noiseSuppression" [(ngModel)]="auxAudioCaptureOptions.noiseSuppression" [style.fontSize.px]="14">noiseSuppression</mat-checkbox>
<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" [style.fontSize.px]="14">
<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" [style.fontSize.px]="14">
<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" [style.fontSize.px]="14">
<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" [style.fontSize.px]="14">
<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" [style.fontSize.px]="14">
<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>
@ -90,20 +81,20 @@
<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">False (no screen)</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" [style.fontSize.px]="14">video</mat-checkbox>
<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-checkbox id="screenShare-audio" [(ngModel)]="screenShareCaptureOptions!.audio" [style.fontSize.px]="14">audio</mat-checkbox>
<mat-checkbox id="screenShare-preferCurrentTab" [(ngModel)]="screenShareCaptureOptions!.preferCurrentTab" [style.fontSize.px]="14">preferCurrentTab</mat-checkbox>
<mat-checkbox id="screenShare-suppressLocalAudioPlayback" [(ngModel)]="screenShareCaptureOptions!.suppressLocalAudioPlayback" [style.fontSize.px]="14">suppressLocalAudioPlayback</mat-checkbox>
<mat-form-field id="screenShare-contentHint">
<mat-label>contentHint</mat-label>
<mat-select [(value)]="screenShareCaptureOptions!.contentHint">
@ -128,43 +119,59 @@
<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>
</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-backupCodec" [(ngModel)]="trackPublishOptions.backupCodec" [style.fontSize.px]="14">backupCodec</mat-checkbox>
<mat-checkbox id="trackPublish-dtx" [(ngModel)]="trackPublishOptions.dtx" [style.fontSize.px]="14">dtx</mat-checkbox>
<mat-checkbox id="trackPublish-forceStereo" [(ngModel)]="trackPublishOptions.forceStereo" [style.fontSize.px]="14">forceStereo</mat-checkbox>
<mat-form-field class="inner-text" [style.fontSize.px]="14">
<mat-label>name</mat-label>
<input matInput id="trackPublish-name" placeholder="name" [(ngModel)]="trackPublishOptions.name"/>
<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">{{codec}}</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox id="trackPublish-red" [(ngModel)]="trackPublishOptions.red" [style.fontSize.px]="14">red</mat-checkbox>
<mat-form-field id="trackPublish-scalabilityMode" [style.fontSize.px]="14">
<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">{{mode}}</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox id="trackPublish-simulcast" [(ngModel)]="trackPublishOptions.simulcast" [style.fontSize.px]="14">simulcast</mat-checkbox>
<mat-form-field id="trackPublish-source" [style.fontSize.px]="14">
<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-checkbox id="trackPublish-stopMicTrackOnMute" [(ngModel)]="trackPublishOptions.stopMicTrackOnMute" [style.fontSize.px]="14">stopMicTrackOnMute</mat-checkbox>
<mat-form-field id="trackPublish-stream" [style.fontSize.px]="14">
<mat-form-field id="trackPublish-stream">
<mat-label>stream</mat-label>
<input matInput id="trackPublish-stream" placeholder="stream" [(ngModel)]="trackPublishOptions.stream"/>
</mat-form-field>
<mat-form-field id="trackPublish-videoCodec" [style.fontSize.px]="14">
<mat-label>videoCodec</mat-label>
<mat-select [(value)]="trackPublishOptions.videoCodec">
<mat-option *ngFor="let codec of ['vp8','h264','vp9','av1']" [value]="codec">{{codec}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</mat-dialog-content>

View File

@ -23,6 +23,9 @@ export class OptionsDialogComponent {
shareScreen = false;
screenShareCaptureOptions?: ScreenShareCaptureOptions;
trackPublishOptions?: TrackPublishOptions;
allowDisablingAudio = true;
allowDisablingVideo = true;
allowDisablingScreen = true;
videoOption: true | false | 'custom';
audioOption: true | false | 'custom';
@ -32,6 +35,7 @@ export class OptionsDialogComponent {
auxAudioCaptureOptions: AudioCaptureOptions;
auxScreenDisplaySurface: 'NONE' | 'window' | 'browser' | 'monitor';
customScreenShareResolution: boolean = false;
ENUMERATION_SOURCE = Object.keys(Track.Source);
@ -44,6 +48,9 @@ export class OptionsDialogComponent {
shareScreen: boolean;
screenShareCaptureOptions?: ScreenShareCaptureOptions;
trackPublishOptions?: TrackPublishOptions;
allowDisablingAudio?: boolean;
allowDisablingVideo?: boolean;
allowDisablingScreen?: boolean;
}
) {
this.roomOptions = data.roomOptions;
@ -51,7 +58,8 @@ export class OptionsDialogComponent {
this.shareScreen = data.shareScreen;
this.screenShareCaptureOptions = data.screenShareCaptureOptions;
this.trackPublishOptions = data.trackPublishOptions;
if (typeof this.createLocalTracksOptions?.video !== 'boolean') {
if (this.createLocalTracksOptions !== undefined) {
if (typeof this.createLocalTracksOptions.video !== 'boolean') {
this.auxVideoCaptureOptions = this.createLocalTracksOptions!
.video as VideoCaptureOptions;
this.videoOption = 'custom';
@ -67,16 +75,29 @@ export class OptionsDialogComponent {
this.audioOption = this.createLocalTracksOptions.audio;
this.auxAudioCaptureOptions = new Room().options.audioCaptureDefaults!;
}
}
if (this.shareScreen) {
if (this.screenShareCaptureOptions == undefined) {
this.screenOption = false;
} else if (Object.keys(this.screenShareCaptureOptions).length > 0) {
this.screenOption = 'custom';
if (this.screenShareCaptureOptions.resolution) {
this.customScreenShareResolution = true;
}
} else {
this.screenOption = true;
this.screenShareCaptureOptions = {};
}
}
if (this.data.allowDisablingAudio === false) {
this.allowDisablingAudio = false;
}
if (this.data.allowDisablingVideo === false) {
this.allowDisablingVideo = false;
}
if (this.data.allowDisablingScreen === false) {
this.allowDisablingScreen = false;
}
}
returnValues() {
@ -117,8 +138,21 @@ export class OptionsDialogComponent {
screenOptionChanged(event: MatRadioChange) {
if (event.value === 'custom' && !this.screenShareCaptureOptions) {
this.screenShareCaptureOptions = {
video: true
video: true,
};
}
}
handleCustomScreenResolutionChange() {
if (this.customScreenShareResolution) {
if (!this.screenShareCaptureOptions!.resolution) {
this.screenShareCaptureOptions!.resolution = {
width: 1920,
height: 1080,
};
}
} else {
delete this.screenShareCaptureOptions!.resolution;
}
}
}

View File

@ -0,0 +1,17 @@
.resolution-div {
border: 1px solid #e0e0e0;
padding: 5px 5px 5px 5px;
border-radius: 5px;
width: fit-content;
margin-top: 8px;
}
.resolution-title {
margin-top: 2px;
}
mat-form-field {
font-size: 124x;
width: 100px;
margin-right: 4px;
}

View File

@ -0,0 +1,19 @@
<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>
</div>

View File

@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { VideoResolutionComponent } from './video-resolution.component';
describe('VideoResolutionComponent', () => {
let component: VideoResolutionComponent;
let fixture: ComponentFixture<VideoResolutionComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [VideoResolutionComponent]
});
fixture = TestBed.createComponent(VideoResolutionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,30 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-video-resolution',
templateUrl: './video-resolution.component.html',
styleUrls: ['./video-resolution.component.css'],
})
export class VideoResolutionComponent {
@Input() componentId: string;
@Input() showTitle = true;
@Input() width: number;
@Input() height: number;
@Input() frameRate?: number;
@Input() aspectRatio?: number;
@Output() resolutionChanged: EventEmitter<{
width: number;
height: number;
frameRate?: number;
aspectRatio?: number;
}> = new EventEmitter();
emitChanges() {
this.resolutionChanged.emit({
width: this.width,
height: this.height,
frameRate: this.frameRate,
aspectRatio: this.aspectRatio,
});
}
}

View File

@ -83,10 +83,10 @@
</div>
</div>
<div>
<app-participant class="local-participant" [participant]="room.localParticipant"
<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" [index]="index" (sendDataToOneParticipant)="sendData($event)"></app-participant>
[participant]="participant.value" [room]="room" [index]="index" (sendDataToOneParticipant)="sendData($event)"></app-participant>
</div>
</mat-card-content>

View File

@ -166,10 +166,17 @@ export class OpenviduInstanceComponent {
);
if (this.roomConf.publisher) {
const tracks: LocalTrack[] =
await this.room.localParticipant.createTracks(
const tracks: LocalTrack[] = [];
if (
this.createLocalTracksOptions.audio ||
this.createLocalTracksOptions.video
) {
tracks.push(
...(await this.room.localParticipant.createTracks(
this.createLocalTracksOptions
))
);
}
if (this.screenShareCaptureOptions) {
const screenTracks: LocalTrack[] =
await this.room.localParticipant.createScreenTracks(
@ -1026,6 +1033,23 @@ export class OpenviduInstanceComponent {
this.createLocalTracksOptions = result.createLocalTracksOptions;
this.screenShareCaptureOptions = result.screenShareCaptureOptions;
this.trackPublishOptions = result.trackPublishOptions;
if (
this.createLocalTracksOptions.audio != undefined &&
typeof this.createLocalTracksOptions.audio !== 'boolean'
) {
this.roomOptions.audioCaptureDefaults =
this.createLocalTracksOptions.audio;
}
if (
this.createLocalTracksOptions.video != undefined &&
typeof this.createLocalTracksOptions.video !== 'boolean'
) {
this.roomOptions.videoCaptureDefaults =
this.createLocalTracksOptions.video;
}
if (this.trackPublishOptions != undefined) {
this.roomOptions.publishDefaults = this.trackPublishOptions;
}
}
});
}

View File

@ -9,7 +9,7 @@
</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="New video track">more_vert</mat-icon>
<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">
@ -17,7 +17,7 @@
</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="New video track">more_vert</mat-icon>
<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">
@ -25,7 +25,11 @@
</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="New video track">more_vert</mat-icon>
<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>

View File

@ -1,7 +1,9 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import {
AudioCaptureOptions,
ConnectionQuality,
CreateLocalTracksOptions,
DataPacket_Kind,
LocalAudioTrack,
LocalParticipant,
@ -12,11 +14,13 @@ import {
ParticipantEvent,
RemoteTrack,
RemoteTrackPublication,
Room,
ScreenShareCaptureOptions,
SubscriptionError,
Track,
TrackEvent,
TrackPublication,
TrackPublishOptions,
VideoCaptureOptions,
createLocalAudioTrack,
createLocalScreenTracks,
@ -28,6 +32,7 @@ import {
TestAppEvent,
TestFeedService,
} from 'src/app/services/test-feed.service';
import { OptionsDialogComponent } from '../dialogs/options-dialog/options-dialog.component';
@Component({
selector: 'app-participant',
@ -38,6 +43,9 @@ export class ParticipantComponent {
@Input()
participant: Participant;
@Input()
room: Room;
@Input()
index: number;
@ -48,33 +56,57 @@ export class ParticipantComponent {
events: TestAppEvent[] = [];
videoCaptureOptions: VideoCaptureOptions;
audioCaptureOptions: AudioCaptureOptions;
screenShareCaptureOptions: ScreenShareCaptureOptions = { audio: true };
createLocalTracksOptions: CreateLocalTracksOptions;
screenShareCaptureOptions: ScreenShareCaptureOptions = {};
trackPublishOptions?: TrackPublishOptions;
private decoder = new TextDecoder();
constructor(private testFeedService: TestFeedService) {}
constructor(
private testFeedService: TestFeedService,
private dialog: MatDialog
) {}
ngOnInit() {
this.setupParticipantEventListeners();
this.localParticipant = this.participant.isLocal
? (this.participant as LocalParticipant)
: undefined;
this.createLocalTracksOptions = {
audio: JSON.parse(JSON.stringify(this.room.options.audioCaptureDefaults)),
video: JSON.parse(JSON.stringify(this.room.options.videoCaptureDefaults)),
};
this.trackPublishOptions = JSON.parse(
JSON.stringify(this.room.options.publishDefaults)
);
}
async addVideoTrack() {
const options =
this.createLocalTracksOptions.video === true
? undefined
: (this.createLocalTracksOptions.video as VideoCaptureOptions);
const localVideoTrack: LocalVideoTrack = await createLocalVideoTrack(
this.videoCaptureOptions
options
);
(this.participant as LocalParticipant).publishTrack(
localVideoTrack,
this.trackPublishOptions
);
(this.participant as LocalParticipant).publishTrack(localVideoTrack);
}
async addAudioTrack() {
const options =
this.createLocalTracksOptions.audio === true
? undefined
: (this.createLocalTracksOptions.audio as AudioCaptureOptions);
const localAudioTrack: LocalAudioTrack = await createLocalAudioTrack(
this.audioCaptureOptions
options
);
(this.participant as LocalParticipant).publishTrack(
localAudioTrack,
this.trackPublishOptions
);
(this.participant as LocalParticipant).publishTrack(localAudioTrack);
}
async addScreenTrack() {
@ -82,15 +114,79 @@ export class ParticipantComponent {
this.screenShareCaptureOptions
);
localScreenTracks.forEach((track) =>
(this.participant as LocalParticipant).publishTrack(track)
(this.participant as LocalParticipant).publishTrack(
track,
this.trackPublishOptions
)
);
}
openVideoTrackOptionsDialog() {}
openVideoTrackOptionsDialog() {
const dialogRef = this.dialog.open(OptionsDialogComponent, {
data: {
createLocalTracksOptions: {
video: this.createLocalTracksOptions.video,
},
allowDisablingVideo: false,
},
});
dialogRef.afterClosed().subscribe((result) => {
if (!!result) {
if (typeof result.createLocalTracksOptions.video === 'boolean') {
this.createLocalTracksOptions.video =
this.room.options.videoCaptureDefaults!;
} else {
this.createLocalTracksOptions.video = result.createLocalTracksOptions
.video as VideoCaptureOptions;
}
}
});
}
openAudioTrackOptionsDialog() {}
openAudioTrackOptionsDialog() {
const dialogRef = this.dialog.open(OptionsDialogComponent, {
data: {
createLocalTracksOptions: {
audio: this.createLocalTracksOptions.audio,
},
allowDisablingAudio: false,
},
});
dialogRef.afterClosed().subscribe((result) => {
if (!!result) {
this.createLocalTracksOptions.audio =
result.createLocalTracksOptions.audio;
}
});
}
openScreenTrackOptionsDialog() {}
openScreenTrackOptionsDialog() {
const dialogRef = this.dialog.open(OptionsDialogComponent, {
data: {
shareScreen: true,
screenShareCaptureOptions: this.screenShareCaptureOptions,
allowDisablingScreen: false,
},
});
dialogRef.afterClosed().subscribe((result) => {
if (!!result) {
this.screenShareCaptureOptions = result.screenShareCaptureOptions;
}
});
}
openTrackPublishOptionsDialog() {
const dialogRef = this.dialog.open(OptionsDialogComponent, {
data: {
trackPublishOptions: this.trackPublishOptions,
},
});
dialogRef.afterClosed().subscribe((result) => {
if (!!result) {
this.trackPublishOptions = result.trackPublishOptions;
}
});
}
/**
* [ParticipantEventCallbacks]

View File

@ -53,10 +53,7 @@ export class TestScenariosComponent implements OnInit, OnDestroy {
users: User[] = [];
roomOptions: RoomOptions = {
adaptiveStream: true,
dynacast: true,
};
roomOptions: RoomOptions;
roomConnectOptions: RoomConnectOptions = {
autoSubscribe: false,
};
@ -70,7 +67,7 @@ export class TestScenariosComponent implements OnInit, OnDestroy {
},
audio: false,
};
trackPublishOptions: TrackPublishOptions = {};
trackPublishOptions: TrackPublishOptions;
constructor(
private livekitParamsService: LivekitParamsService,

View File

@ -8,7 +8,8 @@ body {
}
body {
font-family: Roboto, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif;
font-family: Roboto, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial,
Lucida Grande, sans-serif;
}
a {
@ -76,7 +77,7 @@ button {
display: flex !important;
}
app-participant:last-child>.participant-container {
app-participant:last-child > .participant-container {
margin-bottom: 0;
}
@ -100,3 +101,7 @@ button.mat-icon-custom .mat-mdc-button-touch-target {
width: 100%;
margin-top: 12px;
}
app-options-dialog .mat-mdc-form-field-infix {
width: 140px;
}