diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts index 15382649..c605b9e8 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts @@ -37,7 +37,7 @@ export class AudioDevicesComponent implements OnInit, OnDestroy { this.subscribeToParticipantMediaProperties(); if (this.openviduService.isSessionConnected()) { // Updating devices only with session connected - await this.deviceSrv.initializeDevices(); + await this.deviceSrv.refreshDevices(); } this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable(); if(this.hasAudioDevices) { diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts index 0d48b644..04a5610d 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts @@ -44,8 +44,10 @@ export class VideoDevicesComponent implements OnInit, OnDestroy { this.subscribeToParticipantMediaProperties(); if (this.openviduService.isSessionConnected()) { // Updating devices only with session connected - await this.deviceSrv.initializeDevices(); + await this.deviceSrv.refreshDevices(); } + + this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable(); if(this.hasVideoDevices){ this.cameras = this.deviceSrv.getCameras(); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts index 705f04e1..ef785e4b 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts @@ -464,10 +464,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni await this.handlePublisherError(e); resolve(); }); - publisher.once('accessAllowed', async () => { - await this.handlePublisherSuccess(); - resolve(); - }); + publisher.once('accessAllowed', () => resolve()); } } catch (error) { this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true); @@ -668,39 +665,18 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni let message: string = ''; if (e.name === OpenViduErrorName.DEVICE_ALREADY_IN_USE) { this.log.w('Video device already in use. Disabling video device...'); - // Allow access to the room with only mic if camera device is already in use + // Disabling video device + // Allow access to the room with only mic this.deviceSrv.disableVideoDevices(); return await this.initwebcamPublisher(); } - if (e.name === OpenViduErrorName.DEVICE_ACCESS_DENIED) { - message = this.translateService.translate('ERRORS.MEDIA_ACCESS'); - this.deviceSrv.disableVideoDevices(); - this.deviceSrv.disableAudioDevices(); - return await this.initwebcamPublisher(); - } else if (e.name === OpenViduErrorName.NO_INPUT_SOURCE_SET) { + if (e.name === OpenViduErrorName.NO_INPUT_SOURCE_SET) { message = this.translateService.translate('ERRORS.DEVICE_NOT_FOUND'); } this.actionService.openDialog(e.name.replace(/_/g, ' '), message, true); this.log.e(e.message); } - private async handlePublisherSuccess() { - // The devices are initialized without labels in Firefox. - // We need to force an update after publisher is allowed. - if (this.deviceSrv.areEmptyLabels()) { - await this.deviceSrv.forceInitDevices(); - if (this.deviceSrv.hasAudioDeviceAvailable()) { - const audioLabel = this.participantService.getMyCameraPublisher()?.stream?.getMediaStream()?.getAudioTracks()[0]?.label; - this.deviceSrv.setMicSelected(audioLabel); - } - - if (this.deviceSrv.hasVideoDeviceAvailable()) { - const videoLabel = this.participantService.getMyCameraPublisher()?.stream?.getMediaStream()?.getVideoTracks()[0]?.label; - this.deviceSrv.setCameraSelected(videoLabel); - } - } - } - private subscribeToVideconferenceDirectives() { this.prejoinSub = this.libService.prejoin.subscribe((value: boolean) => { this.showPrejoin = value; diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts index 86bc014b..aadc7028 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { Device, OpenVidu, OpenViduError, OpenViduErrorName } from 'openvidu-browser'; -import { CameraType, DeviceType, CustomDevice } from '../../models/device.model'; +import { CameraType, CustomDevice, DeviceType } from '../../models/device.model'; import { ILogger } from '../../models/logger.model'; import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.service'; @@ -23,13 +23,14 @@ export class DeviceService { private cameraSelected: CustomDevice | null; private microphoneSelected: CustomDevice | null; private log: ILogger; - private videoDevicesDisabled: boolean; - private audioDevicesDisabled: boolean; + private videoDevicesEnabled: boolean = true; + private audioDevicesEnabled: boolean = true; // Initialized with Storage.VIDEO_MUTED info saved on storage private _isVideoMuted: boolean; // Initialized with Storage.AUDIO_MUTED info saved on storage private _isAudioMuted: boolean; + // Whether the media devices permission have been rejected or not private deviceAccessDeniedError: boolean = false; constructor( @@ -42,41 +43,50 @@ export class DeviceService { } /** - * Initialize media devices and devices selected checking in local storage (if exists) or + * Initialize media devices and select a devices checking in local storage (if exists) or * first devices found by default */ async forceInitDevices() { this.clear(); + this.OV = new OpenVidu(); + try { - this.OV = new OpenVidu(); - this.devices = await this.OV.getDevices(); - if(this.devices?.some(device => !device.deviceId || !device.label)){ - // Forcing media permissions request. - // Sometimes, browser doesn't request the media permissions. - await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined }); - } - - await this.initializeDevices(); - this.updateAudioDeviceSelected(); - this.updateVideoDeviceSelected(); - - this._isVideoMuted = this.storageSrv.isVideoMuted() || this.libSrv.videoMuted.getValue(); - this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue(); - - this.log.d('Media devices', this.cameras, this.microphones); + // if (this.devices?.some((device) => !device.deviceId || !device.label)) { + // Forcing media permissions request. + // Sometimes, browser doesn't request the media permissions. + await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined }); + // } + this.devices = await this.getOpenViduDevices(); } catch (error) { this.deviceAccessDeniedError = (error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED; + if (this.deviceAccessDeniedError) { + this.disableVideoDevices(); + this.disableAudioDevices(); + } + } finally { + if (this.deviceAccessDeniedError) { + this.log.w('Media devices permissions were not granted.'); + } else { + this.initializeCustomDevices(); + this.updateAudioDeviceSelected(); + this.updateVideoDeviceSelected(); + + this._isVideoMuted = this.storageSrv.isVideoMuted() || this.libSrv.videoMuted.getValue(); + this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue(); + + this.log.d('Media devices', this.cameras, this.microphones); + } } } /** - * Initialize only the media devices available + * Check and update the media devices devices available */ - async initializeDevices() { - if(this.devices?.some(device => !device.deviceId || !device.label)){ - this.devices = await this.OV?.getDevices() as Device []; + async refreshDevices() { + if (!this.deviceAccessDeniedError) { + this.devices = await this.getOpenViduDevices(); + this.initializeCustomDevices(); } - this.initializeCustomDevices(); } private initializeCustomDevices(updateSelected: boolean = true): void { @@ -194,27 +204,23 @@ export class DeviceService { } hasVideoDeviceAvailable(): boolean { - return !this.videoDevicesDisabled && this.cameras.length > 0; + return this.videoDevicesEnabled && this.cameras.length > 0; } hasAudioDeviceAvailable(): boolean { - return !this.audioDevicesDisabled && this.microphones.length > 0; + return this.audioDevicesEnabled && this.microphones.length > 0; } cameraNeedsMirror(deviceField: string): boolean { return this.getCameraByDeviceField(deviceField)?.type === CameraType.FRONT; } - areEmptyLabels(): boolean { - return !!this.cameras.find((device) => device.label === '') || !!this.microphones.find((device) => device.label === ''); - } - disableVideoDevices() { - this.videoDevicesDisabled = true; + this.videoDevicesEnabled = false; } disableAudioDevices() { - this.audioDevicesDisabled = true; + this.audioDevicesEnabled = false; } clear() { @@ -224,8 +230,8 @@ export class DeviceService { this.microphones = []; this.cameraSelected = null; this.microphoneSelected = null; - this.videoDevicesDisabled = false; - this.audioDevicesDisabled = false; + this.videoDevicesEnabled = true; + this.audioDevicesEnabled = true; } private getCameraByDeviceField(deviceField: any): CustomDevice { @@ -257,4 +263,9 @@ export class DeviceService { private saveMicrophoneToStorage(mic: CustomDevice) { this.storageSrv.setAudioDevice(mic); } + + private async getOpenViduDevices(): Promise { + let devices = (await this.OV?.getDevices()) || []; + return devices.filter((d: Device) => !!d.label && !!d.deviceId); + } }