From 7eedba795bb8ee132c15beda2e344545270f43e2 Mon Sep 17 00:00:00 2001
From: csantosm <4a.santos@gmail.com>
Date: Thu, 10 Mar 2022 14:12:43 +0100
Subject: [PATCH] openvidu-components: Added prejoin drective
- Hide/show prejoin page
- Refactored prejoin component
- Moved the participant initialization to videoconference
- Set necessary delay for the correct layout initialization
---
.../lib/components/layout/layout.component.ts | 8 +-
.../components/pre-join/pre-join.component.ts | 80 +++----------
.../components/session/session.component.ts | 4 -
.../components/toolbar/toolbar.component.ts | 10 +-
.../videoconference.component.html | 8 +-
.../videoconference.component.ts | 109 ++++++++++++++++--
.../directives/api/api.directive.module.ts | 4 +-
.../api/videoconference.directive.ts | 23 ++++
.../src/lib/models/participant.model.ts | 2 +-
.../config/openvidu-angular.config.service.ts | 10 +-
10 files changed, 160 insertions(+), 98 deletions(-)
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";