mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Refactor audio and video device components to use reactive signals for improved performance and cleaner code
parent
f4264a2a8a
commit
ed64c3a305
|
|
@ -1,18 +1,18 @@
|
||||||
<div class="audio-device-selector" [class.compact]="compact">
|
<div class="audio-device-selector" [class.compact]="compact">
|
||||||
<!-- Unified Device Button (Compact Mode) -->
|
<!-- Unified Device Button (Compact Mode) -->
|
||||||
@if (compact) {
|
@if (compact) {
|
||||||
@if (hasAudioDevices) {
|
@if (hasAudioDevices()) {
|
||||||
<div class="unified-device-button">
|
<div class="unified-device-button">
|
||||||
<!-- Main toggle button -->
|
<!-- Main toggle button -->
|
||||||
<button
|
<button
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
class="toggle-section"
|
class="toggle-section"
|
||||||
[disabled]="!hasAudioDevices || microphoneStatusChanging"
|
[disabled]="!hasAudioDevices() || microphoneStatusChanging"
|
||||||
[class.device-enabled]="isMicrophoneEnabled"
|
[class.device-enabled]="isMicrophoneEnabled"
|
||||||
[class.device-disabled]="!isMicrophoneEnabled"
|
[class.device-disabled]="!isMicrophoneEnabled"
|
||||||
(click)="toggleMic($event)"
|
(click)="toggleMic($event)"
|
||||||
[matTooltip]="isMicrophoneEnabled ? ('TOOLBAR.MUTE_AUDIO' | translate) : ('TOOLBAR.UNMUTE_AUDIO' | translate)"
|
[matTooltip]="isMicrophoneEnabled ? ('TOOLBAR.MUTE_AUDIO' | translate) : ('TOOLBAR.UNMUTE_AUDIO' | translate)"
|
||||||
[matTooltipDisabled]="!hasAudioDevices"
|
[matTooltipDisabled]="!hasAudioDevices()"
|
||||||
id="microphone-button"
|
id="microphone-button"
|
||||||
>
|
>
|
||||||
<mat-icon [id]="isMicrophoneEnabled ? 'mic' : 'mic_off'">{{ isMicrophoneEnabled ? 'mic' : 'mic_off' }}</mat-icon>
|
<mat-icon [id]="isMicrophoneEnabled ? 'mic' : 'mic_off'">{{ isMicrophoneEnabled ? 'mic' : 'mic_off' }}</mat-icon>
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
<!-- Normal Mode - Input Style Selector -->
|
<!-- Normal Mode - Input Style Selector -->
|
||||||
<div class="normal-device-selector">
|
<div class="normal-device-selector">
|
||||||
<!-- Input-style Device Selector -->
|
<!-- Input-style Device Selector -->
|
||||||
<div class="device-input-selector" [class.disabled]="!hasAudioDevices || !isMicrophoneEnabled">
|
<div class="device-input-selector" [class.disabled]="!hasAudioDevices() || !isMicrophoneEnabled">
|
||||||
<!-- When microphone is enabled -->
|
<!-- When microphone is enabled -->
|
||||||
@if (isMicrophoneEnabled) {
|
@if (isMicrophoneEnabled) {
|
||||||
<div class="device-input-selector">
|
<div class="device-input-selector">
|
||||||
|
|
@ -50,23 +50,23 @@
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
id="audio-dropdown"
|
id="audio-dropdown"
|
||||||
class="selector-button"
|
class="selector-button"
|
||||||
[disabled]="microphoneStatusChanging || microphones.length <= 1"
|
[disabled]="microphoneStatusChanging || microphones().length <= 1"
|
||||||
[matMenuTriggerFor]="microphoneMenu"
|
[matMenuTriggerFor]="microphoneMenu"
|
||||||
[attr.aria-expanded]="false"
|
[attr.aria-expanded]="false"
|
||||||
>
|
>
|
||||||
<mat-icon class="device-icon">mic</mat-icon>
|
<mat-icon class="device-icon">mic</mat-icon>
|
||||||
<span class="selected-device-name">{{ microphoneSelected?.label || 'No microphone selected' }}</span>
|
<span class="selected-device-name">{{ microphoneSelected()?.label || 'No microphone selected' }}</span>
|
||||||
<mat-icon class="dropdown-icon" *ngIf="microphones.length > 1">expand_more</mat-icon>
|
<mat-icon class="dropdown-icon" *ngIf="microphones().length > 1">expand_more</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
@if (hasAudioDevices) {
|
@if (hasAudioDevices()) {
|
||||||
<!-- When microphone is disabled -->
|
<!-- When microphone is disabled -->
|
||||||
<div class="device-input-selector disabled">
|
<div class="device-input-selector disabled">
|
||||||
<div class="selector-button disabled">
|
<div class="selector-button disabled">
|
||||||
<mat-icon class="device-icon">mic_off</mat-icon>
|
<mat-icon class="device-icon">mic_off</mat-icon>
|
||||||
<span class="selected-device-name">
|
<span class="selected-device-name">
|
||||||
{{ !hasAudioDevices ? ('PREJOIN.NO_AUDIO_DEVICE' | translate) : 'Microphone disabled' }}
|
{{ !hasAudioDevices() ? ('PREJOIN.NO_AUDIO_DEVICE' | translate) : 'Microphone disabled' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -84,14 +84,14 @@
|
||||||
|
|
||||||
<!-- Device Selection Menu (Shared) -->
|
<!-- Device Selection Menu (Shared) -->
|
||||||
<mat-menu #microphoneMenu="matMenu" class="device-menu">
|
<mat-menu #microphoneMenu="matMenu" class="device-menu">
|
||||||
@for (microphone of microphones; track microphone.device) {
|
@for (microphone of microphones(); track microphone.device) {
|
||||||
<button
|
<button
|
||||||
mat-menu-item
|
mat-menu-item
|
||||||
id="option-{{ microphone.label }}"
|
id="option-{{ microphone.label }}"
|
||||||
(click)="onMicrophoneSelected({ value: microphone })"
|
(click)="onMicrophoneSelected({ value: microphone })"
|
||||||
[class.selected]="microphone.device === microphoneSelected.device"
|
[class.selected]="microphone.device === microphoneSelected()?.device"
|
||||||
>
|
>
|
||||||
<mat-icon *ngIf="microphone.device === microphoneSelected.device">check</mat-icon>
|
<mat-icon *ngIf="microphone.device === microphoneSelected()?.device">check</mat-icon>
|
||||||
<span>{{ microphone.label }}</span>
|
<span>{{ microphone.label }}</span>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
import { Component, effect, EventEmitter, Input, OnInit, Output, Signal, WritableSignal } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
import { CustomDevice } from '../../../models/device.model';
|
import { CustomDevice } from '../../../models/device.model';
|
||||||
import { ILogger } from '../../../models/logger.model';
|
import { ILogger } from '../../../models/logger.model';
|
||||||
import { ParticipantModel } from '../../../models/participant.model';
|
|
||||||
import { DeviceService } from '../../../services/device/device.service';
|
import { DeviceService } from '../../../services/device/device.service';
|
||||||
import { LoggerService } from '../../../services/logger/logger.service';
|
import { LoggerService } from '../../../services/logger/logger.service';
|
||||||
import { ParticipantService } from '../../../services/participant/participant.service';
|
import { ParticipantService } from '../../../services/participant/participant.service';
|
||||||
|
|
@ -17,19 +15,20 @@ import { StorageService } from '../../../services/storage/storage.service';
|
||||||
styleUrls: ['./audio-devices.component.scss'],
|
styleUrls: ['./audio-devices.component.scss'],
|
||||||
standalone: false
|
standalone: false
|
||||||
})
|
})
|
||||||
export class AudioDevicesComponent implements OnInit, OnDestroy {
|
export class AudioDevicesComponent implements OnInit {
|
||||||
@Input() compact: boolean = false;
|
@Input() compact: boolean = false;
|
||||||
@Output() onAudioDeviceChanged = new EventEmitter<CustomDevice>();
|
@Output() onAudioDeviceChanged = new EventEmitter<CustomDevice>();
|
||||||
@Output() onAudioEnabledChanged = new EventEmitter<boolean>();
|
@Output() onAudioEnabledChanged = new EventEmitter<boolean>();
|
||||||
|
|
||||||
microphoneStatusChanging: boolean;
|
microphoneStatusChanging: boolean = false;
|
||||||
hasAudioDevices: boolean;
|
isMicrophoneEnabled: boolean = false;
|
||||||
isMicrophoneEnabled: boolean;
|
|
||||||
microphoneSelected: CustomDevice | undefined;
|
|
||||||
microphones: CustomDevice[] = [];
|
|
||||||
private localParticipantSubscription: Subscription;
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
|
|
||||||
|
// Expose signals directly from service (reactive)
|
||||||
|
protected readonly microphones: WritableSignal<CustomDevice[]>;
|
||||||
|
protected readonly microphoneSelected: WritableSignal<CustomDevice | undefined>;
|
||||||
|
protected readonly hasAudioDevices: Signal<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private deviceSrv: DeviceService,
|
private deviceSrv: DeviceService,
|
||||||
private storageSrv: StorageService,
|
private storageSrv: StorageService,
|
||||||
|
|
@ -37,24 +36,24 @@ export class AudioDevicesComponent implements OnInit, OnDestroy {
|
||||||
private loggerSrv: LoggerService
|
private loggerSrv: LoggerService
|
||||||
) {
|
) {
|
||||||
this.log = this.loggerSrv.get('AudioDevicesComponent');
|
this.log = this.loggerSrv.get('AudioDevicesComponent');
|
||||||
|
this.microphones = this.deviceSrv.microphones;
|
||||||
|
this.microphoneSelected = this.deviceSrv.microphoneSelected;
|
||||||
|
this.hasAudioDevices = this.deviceSrv.hasAudioDevices;
|
||||||
|
|
||||||
|
// Use effect instead of subscription for reactive updates
|
||||||
|
effect(() => {
|
||||||
|
const participant = this.participantService.localParticipantSignal();
|
||||||
|
if (participant) {
|
||||||
|
this.isMicrophoneEnabled = participant.isMicrophoneEnabled;
|
||||||
|
this.storageSrv.setMicrophoneEnabled(this.isMicrophoneEnabled);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.subscribeToParticipantMediaProperties();
|
|
||||||
this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable();
|
|
||||||
if (this.hasAudioDevices) {
|
|
||||||
this.microphones = this.deviceSrv.getMicrophones();
|
|
||||||
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isMicrophoneEnabled = this.participantService.isMyMicrophoneEnabled();
|
this.isMicrophoneEnabled = this.participantService.isMyMicrophoneEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.microphones = [];
|
|
||||||
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
async toggleMic(event: any) {
|
async toggleMic(event: any) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.microphoneStatusChanging = true;
|
this.microphoneStatusChanging = true;
|
||||||
|
|
@ -72,8 +71,7 @@ export class AudioDevicesComponent implements OnInit, OnDestroy {
|
||||||
this.microphoneStatusChanging = true;
|
this.microphoneStatusChanging = true;
|
||||||
await this.participantService.switchMicrophone(device.device);
|
await this.participantService.switchMicrophone(device.device);
|
||||||
this.deviceSrv.setMicSelected(device.device);
|
this.deviceSrv.setMicSelected(device.device);
|
||||||
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
|
this.onAudioDeviceChanged.emit(this.microphoneSelected());
|
||||||
this.onAudioDeviceChanged.emit(this.microphoneSelected);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log.e('Error switching microphone', error);
|
this.log.e('Error switching microphone', error);
|
||||||
|
|
@ -89,17 +87,4 @@ export class AudioDevicesComponent implements OnInit, OnDestroy {
|
||||||
compareObjectDevices(o1: CustomDevice, o2: CustomDevice): boolean {
|
compareObjectDevices(o1: CustomDevice, o2: CustomDevice): boolean {
|
||||||
return o1.label === o2.label;
|
return o1.label === o2.label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This subscription is necessary to update the microphone status when the user changes it from toolbar and
|
|
||||||
* the settings panel is opened. With this, the microphone status is updated in the settings panel.
|
|
||||||
*/
|
|
||||||
private subscribeToParticipantMediaProperties() {
|
|
||||||
this.localParticipantSubscription = this.participantService.localParticipant$.subscribe((p: ParticipantModel | undefined) => {
|
|
||||||
if (p) {
|
|
||||||
this.isMicrophoneEnabled = p.isMicrophoneEnabled;
|
|
||||||
this.storageSrv.setMicrophoneEnabled(this.isMicrophoneEnabled);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
<div class="video-device-selector" [class.compact]="compact">
|
<div class="video-device-selector" [class.compact]="compact">
|
||||||
<!-- Unified Device Button (Compact Mode) -->
|
<!-- Unified Device Button (Compact Mode) -->
|
||||||
@if (compact) {
|
@if (compact) {
|
||||||
@if (hasVideoDevices) {
|
@if (hasVideoDevices()) {
|
||||||
<div class="unified-device-button">
|
<div class="unified-device-button">
|
||||||
<!-- Main toggle button -->
|
<!-- Main toggle button -->
|
||||||
<button
|
<button
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
class="toggle-section"
|
class="toggle-section"
|
||||||
[disabled]="!hasVideoDevices || cameraStatusChanging"
|
[disabled]="!hasVideoDevices() || cameraStatusChanging"
|
||||||
[class.device-enabled]="isCameraEnabled"
|
[class.device-enabled]="isCameraEnabled"
|
||||||
[class.device-disabled]="!isCameraEnabled"
|
[class.device-disabled]="!isCameraEnabled"
|
||||||
(click)="toggleCam($event)"
|
(click)="toggleCam($event)"
|
||||||
[matTooltip]="isCameraEnabled ? ('TOOLBAR.STOP_VIDEO' | translate) : ('TOOLBAR.START_VIDEO' | translate)"
|
[matTooltip]="isCameraEnabled ? ('TOOLBAR.STOP_VIDEO' | translate) : ('TOOLBAR.START_VIDEO' | translate)"
|
||||||
[matTooltipDisabled]="!hasVideoDevices"
|
[matTooltipDisabled]="!hasVideoDevices()"
|
||||||
id="camera-button"
|
id="camera-button"
|
||||||
>
|
>
|
||||||
<mat-icon [id]="isCameraEnabled ? 'videocam' : 'videocam_off'">
|
<mat-icon [id]="isCameraEnabled ? 'videocam' : 'videocam_off'">
|
||||||
|
|
@ -51,15 +51,15 @@
|
||||||
id="video-dropdown"
|
id="video-dropdown"
|
||||||
class="selector-button"
|
class="selector-button"
|
||||||
[matMenuTriggerFor]="cameraMenu"
|
[matMenuTriggerFor]="cameraMenu"
|
||||||
[disabled]="cameraStatusChanging || cameras.length <= 1"
|
[disabled]="cameraStatusChanging || cameras().length <= 1"
|
||||||
>
|
>
|
||||||
<mat-icon class="device-icon">videocam</mat-icon>
|
<mat-icon class="device-icon">videocam</mat-icon>
|
||||||
<span class="selected-device-name">{{ cameraSelected?.label || 'No camera selected' }}</span>
|
<span class="selected-device-name">{{ cameraSelected()?.label || 'No camera selected' }}</span>
|
||||||
<mat-icon class="dropdown-icon" *ngIf="cameras.length > 1">expand_more</mat-icon>
|
<mat-icon class="dropdown-icon" *ngIf="cameras().length > 1">expand_more</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
@if (hasVideoDevices) {
|
@if (hasVideoDevices()) {
|
||||||
<!-- Disabled state message -->
|
<!-- Disabled state message -->
|
||||||
<div class="device-input-selector disabled">
|
<div class="device-input-selector disabled">
|
||||||
<div class="selector-button disabled">
|
<div class="selector-button disabled">
|
||||||
|
|
@ -80,14 +80,14 @@
|
||||||
|
|
||||||
<!-- Device Selection Menu (Shared) -->
|
<!-- Device Selection Menu (Shared) -->
|
||||||
<mat-menu #cameraMenu="matMenu" class="device-menu">
|
<mat-menu #cameraMenu="matMenu" class="device-menu">
|
||||||
@for (camera of cameras; track camera.device) {
|
@for (camera of cameras(); track camera.device) {
|
||||||
<button
|
<button
|
||||||
mat-menu-item
|
mat-menu-item
|
||||||
id="option-{{ camera.label }}"
|
id="option-{{ camera.label }}"
|
||||||
(click)="onCameraSelected({ value: camera })"
|
(click)="onCameraSelected({ value: camera })"
|
||||||
[class.selected]="camera.device === cameraSelected?.device"
|
[class.selected]="camera.device === cameraSelected()?.device"
|
||||||
>
|
>
|
||||||
<mat-icon *ngIf="camera.device === cameraSelected?.device" class="check-icon">check</mat-icon>
|
<mat-icon *ngIf="camera.device === cameraSelected()?.device" class="check-icon">check</mat-icon>
|
||||||
<span>{{ camera.label }}</span>
|
<span>{{ camera.label }}</span>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
import { Component, effect, EventEmitter, Input, OnInit, Output, Signal, WritableSignal } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
import { CustomDevice } from '../../../models/device.model';
|
import { CustomDevice } from '../../../models/device.model';
|
||||||
import { ILogger } from '../../../models/logger.model';
|
import { ILogger } from '../../../models/logger.model';
|
||||||
import { ParticipantModel } from '../../../models/participant.model';
|
|
||||||
import { DeviceService } from '../../../services/device/device.service';
|
import { DeviceService } from '../../../services/device/device.service';
|
||||||
import { LoggerService } from '../../../services/logger/logger.service';
|
import { LoggerService } from '../../../services/logger/logger.service';
|
||||||
import { ParticipantService } from '../../../services/participant/participant.service';
|
import { ParticipantService } from '../../../services/participant/participant.service';
|
||||||
|
|
@ -17,18 +15,18 @@ import { StorageService } from '../../../services/storage/storage.service';
|
||||||
styleUrls: ['./video-devices.component.scss'],
|
styleUrls: ['./video-devices.component.scss'],
|
||||||
standalone: false
|
standalone: false
|
||||||
})
|
})
|
||||||
export class VideoDevicesComponent implements OnInit, OnDestroy {
|
export class VideoDevicesComponent implements OnInit {
|
||||||
@Input() compact: boolean = false;
|
@Input() compact: boolean = false;
|
||||||
@Output() onVideoDeviceChanged = new EventEmitter<CustomDevice>();
|
@Output() onVideoDeviceChanged = new EventEmitter<CustomDevice>();
|
||||||
@Output() onVideoEnabledChanged = new EventEmitter<boolean>();
|
@Output() onVideoEnabledChanged = new EventEmitter<boolean>();
|
||||||
@Output() onVideoDevicesLoaded = new EventEmitter<CustomDevice[]>();
|
@Output() onVideoDevicesLoaded = new EventEmitter<CustomDevice[]>();
|
||||||
|
|
||||||
cameraStatusChanging: boolean;
|
cameraStatusChanging: boolean = false;
|
||||||
isCameraEnabled: boolean;
|
isCameraEnabled: boolean = false;
|
||||||
cameraSelected: CustomDevice | undefined;
|
|
||||||
hasVideoDevices: boolean;
|
protected readonly cameras: WritableSignal<CustomDevice[]>;
|
||||||
cameras: CustomDevice[] = [];
|
protected readonly cameraSelected: WritableSignal<CustomDevice | undefined>;
|
||||||
localParticipantSubscription: Subscription;
|
protected readonly hasVideoDevices: Signal<boolean>;
|
||||||
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
|
|
||||||
|
|
@ -39,26 +37,26 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
|
||||||
private loggerSrv: LoggerService
|
private loggerSrv: LoggerService
|
||||||
) {
|
) {
|
||||||
this.log = this.loggerSrv.get('VideoDevicesComponent');
|
this.log = this.loggerSrv.get('VideoDevicesComponent');
|
||||||
|
this.cameras = this.deviceSrv.cameras;
|
||||||
|
this.cameraSelected = this.deviceSrv.cameraSelected;
|
||||||
|
this.hasVideoDevices = this.deviceSrv.hasVideoDevices;
|
||||||
|
|
||||||
|
// Use effect instead of subscription for reactive updates
|
||||||
|
effect(() => {
|
||||||
|
const participant = this.participantService.localParticipantSignal();
|
||||||
|
if (participant) {
|
||||||
|
this.isCameraEnabled = participant.isCameraEnabled;
|
||||||
|
this.storageSrv.setCameraEnabled(this.isCameraEnabled);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.subscribeToParticipantMediaProperties();
|
// Emit initial device list (reactively)
|
||||||
|
this.onVideoDevicesLoaded.emit(this.cameras());
|
||||||
this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable();
|
|
||||||
if (this.hasVideoDevices) {
|
|
||||||
this.cameras = this.deviceSrv.getCameras();
|
|
||||||
this.cameraSelected = this.deviceSrv.getCameraSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onVideoDevicesLoaded.emit(this.cameras);
|
|
||||||
this.isCameraEnabled = this.participantService.isMyCameraEnabled();
|
this.isCameraEnabled = this.participantService.isMyCameraEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnDestroy() {
|
|
||||||
this.cameras = [];
|
|
||||||
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
async toggleCam(event: any) {
|
async toggleCam(event: any) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.cameraStatusChanging = true;
|
this.cameraStatusChanging = true;
|
||||||
|
|
@ -75,14 +73,10 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
// Is New deviceId different from the old one?
|
// Is New deviceId different from the old one?
|
||||||
if (this.deviceSrv.needUpdateVideoTrack(device)) {
|
if (this.deviceSrv.needUpdateVideoTrack(device)) {
|
||||||
|
|
||||||
this.cameraStatusChanging = true;
|
this.cameraStatusChanging = true;
|
||||||
|
|
||||||
await this.participantService.switchCamera(device.device);
|
await this.participantService.switchCamera(device.device);
|
||||||
|
|
||||||
this.deviceSrv.setCameraSelected(device.device);
|
this.deviceSrv.setCameraSelected(device.device);
|
||||||
this.cameraSelected = device;
|
this.onVideoDeviceChanged.emit(this.cameraSelected());
|
||||||
this.onVideoDeviceChanged.emit(this.cameraSelected);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log.e('Error switching camera', error);
|
this.log.e('Error switching camera', error);
|
||||||
|
|
@ -98,17 +92,4 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
|
||||||
compareObjectDevices(o1: CustomDevice, o2: CustomDevice): boolean {
|
compareObjectDevices(o1: CustomDevice, o2: CustomDevice): boolean {
|
||||||
return o1.label === o2.label;
|
return o1.label === o2.label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This subscription is necessary to update the camera status when the user changes it from toolbar and
|
|
||||||
* the settings panel is opened. With this, the camera status is updated in the settings panel.
|
|
||||||
*/
|
|
||||||
private subscribeToParticipantMediaProperties() {
|
|
||||||
this.localParticipantSubscription = this.participantService.localParticipant$.subscribe((p: ParticipantModel | undefined) => {
|
|
||||||
if (p) {
|
|
||||||
this.isCameraEnabled = p.isCameraEnabled;
|
|
||||||
this.storageSrv.setCameraEnabled(this.isCameraEnabled);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -421,9 +421,12 @@ export class OpenViduService {
|
||||||
|
|
||||||
// Video device
|
// Video device
|
||||||
if (videoDeviceId === true) {
|
if (videoDeviceId === true) {
|
||||||
options.video = this.deviceService.hasVideoDeviceAvailable()
|
if (this.deviceService.hasVideoDeviceAvailable()) {
|
||||||
? { deviceId: this.deviceService.getCameraSelected()?.device || 'default' }
|
const selectedCamera = this.deviceService.getCameraSelected();
|
||||||
: false;
|
options.video = { deviceId: selectedCamera?.device || 'default' };
|
||||||
|
} else {
|
||||||
|
options.video = false;
|
||||||
|
}
|
||||||
} else if (videoDeviceId === false) {
|
} else if (videoDeviceId === false) {
|
||||||
options.video = false;
|
options.video = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -433,8 +436,8 @@ export class OpenViduService {
|
||||||
// Audio device
|
// Audio device
|
||||||
if (audioDeviceId === true) {
|
if (audioDeviceId === true) {
|
||||||
if (this.deviceService.hasAudioDeviceAvailable()) {
|
if (this.deviceService.hasAudioDeviceAvailable()) {
|
||||||
audioDeviceId = this.deviceService.getMicrophoneSelected()?.device || 'default';
|
const selectedMic = this.deviceService.getMicrophoneSelected();
|
||||||
(options.audio as AudioCaptureOptions).deviceId = audioDeviceId;
|
(options.audio as AudioCaptureOptions).deviceId = selectedMic?.device || 'default';
|
||||||
} else {
|
} else {
|
||||||
options.audio = false;
|
options.audio = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue