openvidu-components: Refactored device service

pull/748/head
Carlos Santos 2022-10-27 17:25:59 +02:00
parent 46ab59f4b2
commit 36dad0c86d
4 changed files with 54 additions and 65 deletions

View File

@ -37,7 +37,7 @@ export class AudioDevicesComponent implements OnInit, OnDestroy {
this.subscribeToParticipantMediaProperties(); this.subscribeToParticipantMediaProperties();
if (this.openviduService.isSessionConnected()) { if (this.openviduService.isSessionConnected()) {
// Updating devices only with session connected // Updating devices only with session connected
await this.deviceSrv.initializeDevices(); await this.deviceSrv.refreshDevices();
} }
this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable(); this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable();
if(this.hasAudioDevices) { if(this.hasAudioDevices) {

View File

@ -44,8 +44,10 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
this.subscribeToParticipantMediaProperties(); this.subscribeToParticipantMediaProperties();
if (this.openviduService.isSessionConnected()) { if (this.openviduService.isSessionConnected()) {
// Updating devices only with session connected // Updating devices only with session connected
await this.deviceSrv.initializeDevices(); await this.deviceSrv.refreshDevices();
} }
this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable(); this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable();
if(this.hasVideoDevices){ if(this.hasVideoDevices){
this.cameras = this.deviceSrv.getCameras(); this.cameras = this.deviceSrv.getCameras();

View File

@ -464,10 +464,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
await this.handlePublisherError(e); await this.handlePublisherError(e);
resolve(); resolve();
}); });
publisher.once('accessAllowed', async () => { publisher.once('accessAllowed', () => resolve());
await this.handlePublisherSuccess();
resolve();
});
} }
} catch (error) { } catch (error) {
this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true); this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true);
@ -668,39 +665,18 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
let message: string = ''; let message: string = '';
if (e.name === OpenViduErrorName.DEVICE_ALREADY_IN_USE) { if (e.name === OpenViduErrorName.DEVICE_ALREADY_IN_USE) {
this.log.w('Video device already in use. Disabling video device...'); 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(); this.deviceSrv.disableVideoDevices();
return await this.initwebcamPublisher(); return await this.initwebcamPublisher();
} }
if (e.name === OpenViduErrorName.DEVICE_ACCESS_DENIED) { if (e.name === OpenViduErrorName.NO_INPUT_SOURCE_SET) {
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) {
message = this.translateService.translate('ERRORS.DEVICE_NOT_FOUND'); message = this.translateService.translate('ERRORS.DEVICE_NOT_FOUND');
} }
this.actionService.openDialog(e.name.replace(/_/g, ' '), message, true); this.actionService.openDialog(e.name.replace(/_/g, ' '), message, true);
this.log.e(e.message); 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() { private subscribeToVideconferenceDirectives() {
this.prejoinSub = this.libService.prejoin.subscribe((value: boolean) => { this.prejoinSub = this.libService.prejoin.subscribe((value: boolean) => {
this.showPrejoin = value; this.showPrejoin = value;

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Device, OpenVidu, OpenViduError, OpenViduErrorName } from 'openvidu-browser'; 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 { ILogger } from '../../models/logger.model';
import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.service'; import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.service';
@ -23,13 +23,14 @@ export class DeviceService {
private cameraSelected: CustomDevice | null; private cameraSelected: CustomDevice | null;
private microphoneSelected: CustomDevice | null; private microphoneSelected: CustomDevice | null;
private log: ILogger; private log: ILogger;
private videoDevicesDisabled: boolean; private videoDevicesEnabled: boolean = true;
private audioDevicesDisabled: boolean; private audioDevicesEnabled: boolean = true;
// Initialized with Storage.VIDEO_MUTED info saved on storage // Initialized with Storage.VIDEO_MUTED info saved on storage
private _isVideoMuted: boolean; private _isVideoMuted: boolean;
// Initialized with Storage.AUDIO_MUTED info saved on storage // Initialized with Storage.AUDIO_MUTED info saved on storage
private _isAudioMuted: boolean; private _isAudioMuted: boolean;
// Whether the media devices permission have been rejected or not
private deviceAccessDeniedError: boolean = false; private deviceAccessDeniedError: boolean = false;
constructor( constructor(
@ -42,21 +43,31 @@ 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 * first devices found by default
*/ */
async forceInitDevices() { async forceInitDevices() {
this.clear(); this.clear();
try {
this.OV = new OpenVidu(); this.OV = new OpenVidu();
this.devices = await this.OV.getDevices();
if(this.devices?.some(device => !device.deviceId || !device.label)){ try {
// if (this.devices?.some((device) => !device.deviceId || !device.label)) {
// Forcing media permissions request. // Forcing media permissions request.
// Sometimes, browser doesn't request the media permissions. // Sometimes, browser doesn't request the media permissions.
await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined }); await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined });
// }
this.devices = await this.getOpenViduDevices();
} catch (error) {
this.deviceAccessDeniedError = (<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED;
if (this.deviceAccessDeniedError) {
this.disableVideoDevices();
this.disableAudioDevices();
} }
} finally {
await this.initializeDevices(); if (this.deviceAccessDeniedError) {
this.log.w('Media devices permissions were not granted.');
} else {
this.initializeCustomDevices();
this.updateAudioDeviceSelected(); this.updateAudioDeviceSelected();
this.updateVideoDeviceSelected(); this.updateVideoDeviceSelected();
@ -64,20 +75,19 @@ export class DeviceService {
this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue(); this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue();
this.log.d('Media devices', this.cameras, this.microphones); this.log.d('Media devices', this.cameras, this.microphones);
} catch (error) { }
this.deviceAccessDeniedError = (<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED;
} }
} }
/** /**
* Initialize only the media devices available * Check and update the media devices devices available
*/ */
async initializeDevices() { async refreshDevices() {
if(this.devices?.some(device => !device.deviceId || !device.label)){ if (!this.deviceAccessDeniedError) {
this.devices = await this.OV?.getDevices() as Device []; this.devices = await this.getOpenViduDevices();
}
this.initializeCustomDevices(); this.initializeCustomDevices();
} }
}
private initializeCustomDevices(updateSelected: boolean = true): void { private initializeCustomDevices(updateSelected: boolean = true): void {
const FIRST_POSITION = 0; const FIRST_POSITION = 0;
@ -194,27 +204,23 @@ export class DeviceService {
} }
hasVideoDeviceAvailable(): boolean { hasVideoDeviceAvailable(): boolean {
return !this.videoDevicesDisabled && this.cameras.length > 0; return this.videoDevicesEnabled && this.cameras.length > 0;
} }
hasAudioDeviceAvailable(): boolean { hasAudioDeviceAvailable(): boolean {
return !this.audioDevicesDisabled && this.microphones.length > 0; return this.audioDevicesEnabled && this.microphones.length > 0;
} }
cameraNeedsMirror(deviceField: string): boolean { cameraNeedsMirror(deviceField: string): boolean {
return this.getCameraByDeviceField(deviceField)?.type === CameraType.FRONT; return this.getCameraByDeviceField(deviceField)?.type === CameraType.FRONT;
} }
areEmptyLabels(): boolean {
return !!this.cameras.find((device) => device.label === '') || !!this.microphones.find((device) => device.label === '');
}
disableVideoDevices() { disableVideoDevices() {
this.videoDevicesDisabled = true; this.videoDevicesEnabled = false;
} }
disableAudioDevices() { disableAudioDevices() {
this.audioDevicesDisabled = true; this.audioDevicesEnabled = false;
} }
clear() { clear() {
@ -224,8 +230,8 @@ export class DeviceService {
this.microphones = []; this.microphones = [];
this.cameraSelected = null; this.cameraSelected = null;
this.microphoneSelected = null; this.microphoneSelected = null;
this.videoDevicesDisabled = false; this.videoDevicesEnabled = true;
this.audioDevicesDisabled = false; this.audioDevicesEnabled = true;
} }
private getCameraByDeviceField(deviceField: any): CustomDevice { private getCameraByDeviceField(deviceField: any): CustomDevice {
@ -257,4 +263,9 @@ export class DeviceService {
private saveMicrophoneToStorage(mic: CustomDevice) { private saveMicrophoneToStorage(mic: CustomDevice) {
this.storageSrv.setAudioDevice(mic); this.storageSrv.setAudioDevice(mic);
} }
private async getOpenViduDevices(): Promise<Device[]> {
let devices = (await this.OV?.getDevices()) || [];
return devices.filter((d: Device) => !!d.label && !!d.deviceId);
}
} }