diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts index e3f6c8a8..367f3adf 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts @@ -50,10 +50,10 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit { } ngAfterViewInit() { - let timeout: number = null; - if (this.libService.isWebcomponent()) { - timeout = 0; - } + let timeout: number = 0; + // if (this.libService.isWebcomponent()) { + // timeout = 0; + // } this.layoutService.initialize(timeout); this.layoutService.update(timeout); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts index 9ffdb0b6..0a37a394 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts @@ -26,7 +26,6 @@ export class PreJoinComponent implements OnInit, OnDestroy { microphoneSelected: CustomDevice; isVideoMuted: boolean; isAudioMuted: boolean; - screenShareEnabled: boolean; localParticipant: ParticipantAbstractModel; windowSize: number; hasVideoDevices: boolean; @@ -45,7 +44,6 @@ export class PreJoinComponent implements OnInit, OnDestroy { constructor( private layoutService: LayoutService, - private actionService: ActionService, private deviceSrv: DeviceService, private loggerSrv: LoggerService, private openviduService: OpenViduService, @@ -55,22 +53,20 @@ export class PreJoinComponent implements OnInit, OnDestroy { this.log = this.loggerSrv.get('PreJoinComponent'); } - async ngOnInit() { - await this.deviceSrv.initializeDevices(); - this.nickname = this.storageSrv.getNickname() || this.generateRandomNickname(); - const props: ParticipantProperties = { - local: true, - nickname: this.nickname - }; - this.participantService.initLocalParticipant(props); - + ngOnInit() { this.subscribeToLocalParticipantEvents(); - this.openviduService.initialize(); + this.windowSize = window.innerWidth; - this.setDevicesInfo(); - if (this.hasAudioDevices || this.hasVideoDevices) { - await this.initwebcamPublisher(); - } + this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable(); + this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable(); + this.microphones = this.deviceSrv.getMicrophones(); + this.cameras = this.deviceSrv.getCameras(); + this.cameraSelected = this.deviceSrv.getCameraSelected(); + this.microphoneSelected = this.deviceSrv.getMicrophoneSelected(); + + this.isVideoMuted = this.deviceSrv.isVideoMuted(); + this.isAudioMuted = this.deviceSrv.isAudioMuted(); + this.isLoading = false; } @@ -201,7 +197,7 @@ export class PreJoinComponent implements OnInit, OnDestroy { } updateNickname() { - this.nickname = this.nickname === '' ? this.generateRandomNickname() : this.nickname; + this.nickname = this.nickname === '' ? this.participantService.getMyNickname() : this.nickname; this.participantService.setMyNickname(this.nickname); this.storageSrv.setNickname(this.nickname); } @@ -210,33 +206,12 @@ export class PreJoinComponent implements OnInit, OnDestroy { this.onJoinButtonClicked.emit(); } - private setDevicesInfo() { - this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable(); - this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable(); - this.microphones = this.deviceSrv.getMicrophones(); - this.cameras = this.deviceSrv.getCameras(); - this.cameraSelected = this.deviceSrv.getCameraSelected(); - this.microphoneSelected = this.deviceSrv.getMicrophoneSelected(); - - this.isVideoMuted = this.deviceSrv.isVideoMuted(); - this.isAudioMuted = this.deviceSrv.isAudioMuted(); - } - private subscribeToLocalParticipantEvents() { this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p) => { this.localParticipant = p; - this.screenShareEnabled = p.isScreenActive(); }); } - private async initwebcamPublisher() { - const publisher = await this.openviduService.initDefaultPublisher(undefined); - if (publisher) { - // this.handlePublisherSuccess(publisher); - this.handlePublisherError(publisher); - } - } - //? After test in Chrome and Firefox, the devices always have labels. //? It's not longer needed // private handlePublisherSuccess(publisher: Publisher) { @@ -256,33 +231,4 @@ export class PreJoinComponent implements OnInit, OnDestroy { // } // }); // } - - private handlePublisherError(publisher: Publisher) { - publisher.once('accessDenied', (e: any) => { - 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 - this.hasVideoDevices = false; - this.deviceSrv.disableVideoDevices(); - return this.initwebcamPublisher(); - } - if (e.name === OpenViduErrorName.DEVICE_ACCESS_DENIED) { - message = 'Access to media devices was not allowed.'; - this.hasVideoDevices = false; - this.hasAudioDevices = false; - this.deviceSrv.disableVideoDevices(); - this.deviceSrv.disableAudioDevices(); - return this.initwebcamPublisher(); - } else if (e.name === OpenViduErrorName.NO_INPUT_SOURCE_SET) { - message = 'No video or audio devices have been found. Please, connect at least one.'; - } - this.actionService.openDialog(e.name.replace(/_/g, ' '), message, true); - this.log.e(e.message); - }); - } - - private generateRandomNickname(): string { - return 'OpenVidu_User' + Math.floor(Math.random() * 100); - } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts index 7398f80f..ed376e1d 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts @@ -86,10 +86,6 @@ export class SessionComponent implements OnInit { async ngOnInit() { - if (this.openviduService.getWebcamSession() === null) { - this.openviduService.initialize(); - await this.openviduService.initDefaultPublisher(undefined); - } this.session = this.openviduService.getWebcamSession(); this.sessionScreen = this.openviduService.getScreenSession(); this.subscribeToConnectionCreatedAndDestroyed(); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts index 992e6b5d..7410d4af 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts @@ -331,10 +331,12 @@ export class ToolbarComponent implements OnInit, OnDestroy { } protected subscribeToUserMediaProperties() { this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p) => { - this.isWebcamVideoActive = p.isCameraVideoActive(); - this.isWebcamAudioActive = p.isCameraAudioActive(); - this.isScreenShareActive = p.isScreenActive(); - this.cd.markForCheck(); + if(p) { + this.isWebcamVideoActive = p.isCameraVideoActive(); + this.isWebcamAudioActive = p.isCameraAudioActive(); + this.isScreenShareActive = p.isScreenActive(); + this.cd.markForCheck(); + } }); } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html index 8d398511..1a30fc93 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html @@ -1,20 +1,20 @@
-
+
-
+
Joining the room ...
-
+
error {{ errorMessage }}
-
+
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 3b90470e..590b2da7 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 @@ -1,4 +1,17 @@ -import { AfterViewInit, Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; +import { + AfterViewInit, + Component, + ContentChild, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, + TemplateRef, + ViewChild +} from '@angular/core'; +import { OpenViduErrorName } from 'openvidu-browser'; +import { Subscription } from 'rxjs'; import { ChatPanelDirective, LayoutDirective, @@ -11,14 +24,21 @@ import { ToolbarDirective } from '../../directives/template/openvidu-angular.directive'; import { ILogger } from '../../models/logger.model'; +import { ParticipantProperties } from '../../models/participant.model'; +import { ActionService } from '../../services/action/action.service'; +import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service'; +import { DeviceService } from '../../services/device/device.service'; import { LoggerService } from '../../services/logger/logger.service'; +import { OpenViduService } from '../../services/openvidu/openvidu.service'; +import { ParticipantService } from '../../services/participant/participant.service'; +import { StorageService } from '../../services/storage/storage.service'; @Component({ selector: 'ov-videoconference', templateUrl: './videoconference.component.html', styleUrls: ['./videoconference.component.css'] }) -export class VideoconferenceComponent implements OnInit, AfterViewInit { +export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewInit { // *** Toolbar *** @ContentChild(ToolbarDirective) externalToolbar: ToolbarDirective; @ContentChild(ToolbarAdditionalButtonsDirective) externalToolbarAdditionalButtons: ToolbarAdditionalButtonsDirective; @@ -30,7 +50,6 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit { @ContentChild(ParticipantPanelItemDirective) externalParticipantPanelItem: ParticipantPanelItemDirective; @ContentChild(ParticipantPanelItemElementsDirective) externalParticipantPanelItemElements: ParticipantPanelItemElementsDirective; - // *** Layout *** @ContentChild(LayoutDirective) externalLayout: LayoutDirective; @ContentChild(StreamDirective) externalStream: StreamDirective; @@ -69,7 +88,6 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit { webcam: tokens.webcam, screen: tokens.screen }; - this.isSessionAlive = true; } } } @@ -97,17 +115,63 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit { @Output() onSessionCreated = new EventEmitter(); joinSessionClicked: boolean = false; - isSessionAlive: boolean = false; + participantReady: boolean = false; _tokens: { webcam: string; screen: string }; error: boolean = false; errorMessage: string = ''; - + showPrejoin: boolean = true; + private prejoinSub: Subscription; private log: ILogger; - constructor(private loggerSrv: LoggerService) { + constructor( + private loggerSrv: LoggerService, + private storageSrv: StorageService, + private participantService: ParticipantService, + private deviceSrv: DeviceService, + private openviduService: OpenViduService, + private actionService: ActionService, + private libService: OpenViduAngularConfigService + ) { this.log = this.loggerSrv.get('VideoconferenceComponent'); } + async ngOnInit() { + this.subscribeToVideconferenceDirectives(); + await this.deviceSrv.initializeDevices(); + const nickname = this.storageSrv.getNickname() || 'OpenVidu_User' + Math.floor(Math.random() * 100); + const props: ParticipantProperties = { + local: true, + nickname + }; + this.participantService.initLocalParticipant(props); + this.openviduService.initialize(); + + if (this.deviceSrv.hasVideoDeviceAvailable() || this.deviceSrv.hasAudioDeviceAvailable()) { + await this.initwebcamPublisher(); + } + } + + private async initwebcamPublisher() { + try { + const publisher = await this.openviduService.initDefaultPublisher(undefined); + if (publisher) { + publisher.once('accessDenied', (e: any) => { + this.handlePublisherError(e); + }); + publisher.once('accessAllowed', () => { + this.participantReady = true; + }); + } + } catch (error) { + this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true); + this.log.e(error); + } + } + + ngOnDestroy(): void { + if (this.prejoinSub) this.prejoinSub.unsubscribe(); + } + ngAfterViewInit() { if (this.externalToolbar) { this.openviduAngularToolbarTemplate = this.externalToolbar.template; @@ -173,15 +237,13 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit { } } - ngOnInit() {} - _onJoinButtonClicked() { this.joinSessionClicked = true; this.onJoinButtonClicked.emit(); } onLeaveButtonClicked() { this.joinSessionClicked = false; - this.isSessionAlive = false; + this.participantReady = false; this.onToolbarLeaveButtonClicked.emit(); } onCameraButtonClicked() { @@ -203,4 +265,31 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit { onChatPanelButtonClicked() { this.onToolbarChatPanelButtonClicked.emit(); } + + private handlePublisherError(e: any) { + 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 + this.deviceSrv.disableVideoDevices(); + return this.initwebcamPublisher(); + } + if (e.name === OpenViduErrorName.DEVICE_ACCESS_DENIED) { + message = 'Access to media devices was not allowed.'; + this.deviceSrv.disableVideoDevices(); + this.deviceSrv.disableAudioDevices(); + return this.initwebcamPublisher(); + } else if (e.name === OpenViduErrorName.NO_INPUT_SOURCE_SET) { + message = 'No video or audio devices have been found. Please, connect at least one.'; + } + this.actionService.openDialog(e.name.replace(/_/g, ' '), message, true); + this.log.e(e.message); + } + + private subscribeToVideconferenceDirectives() { + this.prejoinSub = this.libService.prejoin.subscribe((value: boolean) => { + this.showPrejoin = value; + // this.cd.markForCheck(); + }); + } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts index c7915d25..2f225899 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts @@ -15,11 +15,12 @@ import { ToolbarDisplayLogoDirective, LogoDirective } from './toolbar.directive'; -import { AudioMutedDirective, MinimalDirective, VideoMutedDirective } from './videoconference.directive'; +import { AudioMutedDirective, MinimalDirective, PrejoinDirective, VideoMutedDirective } from './videoconference.directive'; @NgModule({ declarations: [ MinimalDirective, + PrejoinDirective, VideoMutedDirective, AudioMutedDirective, ToolbarScreenshareButtonDirective, @@ -37,6 +38,7 @@ import { AudioMutedDirective, MinimalDirective, VideoMutedDirective } from './vi ], exports: [ MinimalDirective, + PrejoinDirective, VideoMutedDirective, AudioMutedDirective, ToolbarScreenshareButtonDirective, diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts index cd862ce0..8f28f8f0 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts @@ -23,6 +23,29 @@ export class MinimalDirective implements OnDestroy { } } +@Directive({ + selector: 'ov-videoconference[prejoin]' +}) +export class PrejoinDirective implements OnDestroy { + @Input() set prejoin(value: boolean) { + this.update(value); + } + constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {} + + ngOnDestroy(): void { + this.clear(); + } + clear() { + this.update(true); + } + update(value: boolean) { + if (this.libService.prejoin.getValue() !== value) { + this.libService.prejoin.next(value); + } + } +} + + @Directive({ selector: 'ov-videoconference[videoMuted]' }) diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts index 3e34fd88..94df7e5c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts @@ -51,7 +51,7 @@ export abstract class ParticipantAbstractModel { public isCameraAudioActive(): boolean { const cameraConnection = this.getCameraConnection(); if(cameraConnection) { - return cameraConnection.connected && cameraConnection.streamManager.stream.audioActive; + return cameraConnection.connected && cameraConnection.streamManager?.stream?.audioActive; } return this.isScreenAudioActive();; } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts index 943f23ee..b5004804 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts @@ -11,6 +11,9 @@ export class OpenViduAngularConfigService { minimal = >new BehaviorSubject(false); minimalObs: Observable; + prejoin = >new BehaviorSubject(true); + prejoinObs: Observable; + videoMuted = >new BehaviorSubject(false); videoMutedObs: Observable; audioMuted = >new BehaviorSubject(false); @@ -49,6 +52,7 @@ export class OpenViduAngularConfigService { console.log(this.configuration); if(this.isProduction()) console.log('OpenVidu Angular Production Mode'); this.minimalObs = this.minimal.asObservable(); + this.prejoinObs = this.prejoin.asObservable(); this.videoMutedObs = this.videoMuted.asObservable(); this.audioMutedObs = this.audioMuted.asObservable(); //Toolbar observables @@ -74,9 +78,9 @@ export class OpenViduAngularConfigService { return this.configuration?.production; } - isWebcomponent(): boolean { - return this.configuration?.webcomponent; - } + // isWebcomponent(): boolean { + // return this.configuration?.webcomponent; + // } hasParticipantFactory(): boolean { return typeof this.getConfig().participantFactory === "function";