openvidu-components: Fixed bug requesting devices

pull/750/head
csantosm 2022-08-17 17:54:39 +02:00
parent c0e45e8df7
commit 128dd3cfed
3 changed files with 69 additions and 54 deletions

View File

@ -114,7 +114,7 @@ import { TranslateService } from '../../services/translate/translate.service';
styleUrls: ['./videoconference.component.css'], styleUrls: ['./videoconference.component.css'],
animations: [ animations: [
trigger('inOutAnimation', [ trigger('inOutAnimation', [
transition(':enter', [style({ opacity: 0 }), animate('300ms ease-out', style({ opacity: 1 }))]), transition(':enter', [style({ opacity: 0 }), animate('300ms ease-out', style({ opacity: 1 }))])
// transition(':leave', [style({ opacity: 1 }), animate('50ms ease-in', style({ opacity: 0.9 }))]) // transition(':leave', [style({ opacity: 1 }), animate('50ms ease-in', style({ opacity: 0.9 }))])
]) ])
] ]
@ -286,7 +286,8 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
} else { } else {
this.log.w('No screen token found. Screenshare feature will be disabled'); this.log.w('No screen token found. Screenshare feature will be disabled');
} }
this.loading = false;
this.start();
} }
} }
@ -434,6 +435,9 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
async ngOnInit() { async ngOnInit() {
this.subscribeToVideconferenceDirectives(); this.subscribeToVideconferenceDirectives();
}
private async start() {
await this.deviceSrv.forceInitDevices(); await this.deviceSrv.forceInitDevices();
const nickname = this.externalParticipantName || this.storageSrv.getNickname() || `OpenVidu_User${Math.floor(Math.random() * 100)}`; const nickname = this.externalParticipantName || this.storageSrv.getNickname() || `OpenVidu_User${Math.floor(Math.random() * 100)}`;
this.participantService.initLocalParticipant({ local: true, nickname }); this.participantService.initLocalParticipant({ local: true, nickname });
@ -443,23 +447,31 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
} }
this.isSessionInitialized = true; this.isSessionInitialized = true;
this.onParticipantCreated.emit(this.participantService.getLocalParticipant()); this.onParticipantCreated.emit(this.participantService.getLocalParticipant());
this.loading = false;
} }
private async initwebcamPublisher() { private async initwebcamPublisher(): Promise<void> {
return new Promise(async (resolve, reject) => {
try { try {
const publisher = await this.openviduService.initDefaultPublisher(undefined); const publisher = await this.openviduService.initDefaultPublisher();
if (publisher) { if (publisher) {
publisher.once('accessDenied', (e: any) => this.handlePublisherError(e)); publisher.once('accessDenied', (e: any) => {
this.handlePublisherError(e);
resolve();
});
publisher.once('accessAllowed', async () => { publisher.once('accessAllowed', async () => {
await this.handlePublisherSuccess(); await this.handlePublisherSuccess();
this.participantReady = true; this.participantReady = true;
resolve();
}); });
// publisher.once('streamPlaying', () => (this.streamPlaying = true));
} }
} catch (error) { } catch (error) {
this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true); this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true);
this.log.e(error); this.log.e(error);
reject();
} }
});
} }
async ngOnDestroy() { async ngOnDestroy() {
@ -649,8 +661,9 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
this.onSessionCreated.emit(session); this.onSessionCreated.emit(session);
} }
private handlePublisherError(e: any) { private handlePublisherError(e: any): Promise<void> {
let message: string; let message: string = '';
console.log('ERROR!', e);
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 // Allow access to the room with only mic if camera device is already in use

View File

@ -16,12 +16,12 @@ import { StorageService } from '../storage/storage.service';
providedIn: 'root' providedIn: 'root'
}) })
export class DeviceService { export class DeviceService {
private OV: OpenVidu = null; private OV: OpenVidu | null = null;
private devices: Device[]; private devices: Device[];
private cameras: CustomDevice[] = []; private cameras: CustomDevice[] = [];
private microphones: CustomDevice[] = []; private microphones: CustomDevice[] = [];
private cameraSelected: CustomDevice; private cameraSelected: CustomDevice | null;
private microphoneSelected: CustomDevice; private microphoneSelected: CustomDevice | null;
private log: ILogger; private log: ILogger;
private videoDevicesDisabled: boolean; private videoDevicesDisabled: boolean;
private audioDevicesDisabled: boolean; private audioDevicesDisabled: boolean;
@ -49,13 +49,11 @@ export class DeviceService {
this.clear(); this.clear();
try { try {
this.OV = new OpenVidu(); this.OV = new OpenVidu();
this.devices = await this.OV.getDevices();
if(this.devices?.some(device => !device.deviceId || !device.label)){
// Forcing media permissions request. // Forcing media permissions request.
// Sometimes, browser doens't launch the media permissions modal. // Sometimes, browser doesn't request the media permissions.
const mediaStream = await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined }); await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined });
mediaStream?.getAudioTracks().forEach((track) => track.stop());
mediaStream?.getVideoTracks().forEach((track) => track.stop());
} catch (error) {
this.deviceAccessDeniedError = (<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED;
} }
await this.initializeDevices(); await this.initializeDevices();
@ -66,13 +64,18 @@ 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 * Initialize only the media devices available
*/ */
async initializeDevices() { async initializeDevices() {
this.devices = await this.OV.getDevices(); if(this.devices?.some(device => !device.deviceId || !device.label)){
this.devices = await this.OV?.getDevices() as Device [];
}
this.initializeCustomDevices(); this.initializeCustomDevices();
} }
@ -156,11 +159,11 @@ export class DeviceService {
return this.hasAudioDeviceAvailable() && this._isAudioMuted; return this.hasAudioDeviceAvailable() && this._isAudioMuted;
} }
getCameraSelected(): CustomDevice { getCameraSelected(): CustomDevice | null {
return this.cameraSelected; return this.cameraSelected;
} }
getMicrophoneSelected(): CustomDevice { getMicrophoneSelected(): CustomDevice | null {
return this.microphoneSelected; return this.microphoneSelected;
} }
@ -175,11 +178,11 @@ export class DeviceService {
} }
needUpdateVideoTrack(newVideoSource: string): boolean { needUpdateVideoTrack(newVideoSource: string): boolean {
return this.cameraSelected.device !== newVideoSource; return this.cameraSelected?.device !== newVideoSource;
} }
needUpdateAudioTrack(newAudioSource: string): boolean { needUpdateAudioTrack(newAudioSource: string): boolean {
return this.microphoneSelected.device !== newAudioSource; return this.microphoneSelected?.device !== newAudioSource;
} }
getCameras(): CustomDevice[] { getCameras(): CustomDevice[] {
@ -226,14 +229,14 @@ export class DeviceService {
} }
private getCameraByDeviceField(deviceField: any): CustomDevice { private getCameraByDeviceField(deviceField: any): CustomDevice {
return this.cameras.find((opt: CustomDevice) => opt.device === deviceField || opt.label === deviceField); return <CustomDevice>this.cameras.find((opt: CustomDevice) => opt.device === deviceField || opt.label === deviceField);
} }
private getMicrophoneByDeviceField(deviceField: any): CustomDevice { private getMicrophoneByDeviceField(deviceField: any): CustomDevice {
return this.microphones.find((opt: CustomDevice) => opt.device === deviceField || opt.label === deviceField); return <CustomDevice>this.microphones.find((opt: CustomDevice) => opt.device === deviceField || opt.label === deviceField);
} }
private getMicrophoneFromStogare(): CustomDevice { private getMicrophoneFromStogare(): CustomDevice | undefined {
const storageDevice: CustomDevice = this.storageSrv.getAudioDevice(); const storageDevice: CustomDevice = this.storageSrv.getAudioDevice();
if (!!storageDevice && this.microphones.some((device) => device.device === storageDevice.device)) { if (!!storageDevice && this.microphones.some((device) => device.device === storageDevice.device)) {
return storageDevice; return storageDevice;

View File

@ -19,10 +19,10 @@ import { OpenViduEdition } from '../../models/openvidu.model';
}) })
export class OpenViduService { export class OpenViduService {
private ovEdition: OpenViduEdition; private ovEdition: OpenViduEdition;
protected OV: OpenVidu = null; protected OV: OpenVidu;
protected OVScreen: OpenVidu = null; protected OVScreen: OpenVidu;
protected webcamSession: Session = null; protected webcamSession: Session;
protected screenSession: Session = null; protected screenSession: Session;
protected videoSource = undefined; protected videoSource = undefined;
protected audioSource = undefined; protected audioSource = undefined;
protected log: ILogger; protected log: ILogger;
@ -166,14 +166,14 @@ export class OpenViduService {
* @internal * @internal
* Initialize a publisher checking devices saved on storage or if participant have devices available. * Initialize a publisher checking devices saved on storage or if participant have devices available.
*/ */
async initDefaultPublisher(targetElement: string | HTMLElement): Promise<Publisher> { async initDefaultPublisher(): Promise<Publisher> {
const hasVideoDevices = this.deviceService.hasVideoDeviceAvailable(); const hasVideoDevices = this.deviceService.hasVideoDeviceAvailable();
const hasAudioDevices = this.deviceService.hasAudioDeviceAvailable(); const hasAudioDevices = this.deviceService.hasAudioDeviceAvailable();
const isVideoActive = !this.deviceService.isVideoMuted(); const isVideoActive = !this.deviceService.isVideoMuted();
const isAudioActive = !this.deviceService.isAudioMuted(); const isAudioActive = !this.deviceService.isAudioMuted();
let videoSource = null; let videoSource: string | boolean = false;
let audioSource = null; let audioSource: string | boolean = false;
if (hasVideoDevices) { if (hasVideoDevices) {
// Video is active, assign the device selected // Video is active, assign the device selected
@ -200,7 +200,7 @@ export class OpenViduService {
mirror mirror
}; };
if (hasVideoDevices || hasAudioDevices) { if (hasVideoDevices || hasAudioDevices) {
const publisher = await this.initPublisher(targetElement, properties); const publisher = await this.initPublisher(undefined, properties);
this.participantService.setMyCameraPublisher(publisher); this.participantService.setMyCameraPublisher(publisher);
this.participantService.updateLocalParticipant(); this.participantService.updateLocalParticipant();
return publisher; return publisher;
@ -325,7 +325,7 @@ export class OpenViduService {
const properties: PublisherProperties = { const properties: PublisherProperties = {
videoSource: ScreenType.SCREEN, videoSource: ScreenType.SCREEN,
audioSource: hasAudioDevicesAvailable ? this.deviceService.getMicrophoneSelected().device : null, audioSource: hasAudioDevicesAvailable ? this.deviceService.getMicrophoneSelected().device : false,
publishVideo: true, publishVideo: true,
publishAudio: hasAudio, publishAudio: hasAudio,
mirror: false mirror: false
@ -450,7 +450,6 @@ export class OpenViduService {
} }
} }
//TODO: Uncomment this section when replaceTrack issue is fixed
private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> { private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
let mediaStream: MediaStream; let mediaStream: MediaStream;
const isFirefoxPlatform = this.platformService.isFirefox(); const isFirefoxPlatform = this.platformService.isFirefox();