mirror of https://github.com/OpenVidu/openvidu.git
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 initializationpull/707/head
parent
ab74818579
commit
7eedba795b
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<div id="call-container">
|
||||
<div id="pre-join-container" *ngIf="!joinSessionClicked">
|
||||
<div id="pre-join-container" *ngIf="showPrejoin && participantReady && !joinSessionClicked">
|
||||
<ov-pre-join (onJoinButtonClicked)="_onJoinButtonClicked()"></ov-pre-join>
|
||||
<!-- <ov-user-settings (onJoinClicked)="_onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings> -->
|
||||
</div>
|
||||
|
||||
<div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && !error">
|
||||
<div id="spinner" *ngIf="(joinSessionClicked || !showPrejoin) && !participantReady && !error">
|
||||
<mat-spinner [diameter]="50"></mat-spinner>
|
||||
<span>Joining the room ...</span>
|
||||
</div>
|
||||
|
||||
<div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && error">
|
||||
<div id="spinner" *ngIf="joinSessionClicked && !participantReady && error">
|
||||
<mat-icon class="error-icon">error</mat-icon>
|
||||
<span>{{ errorMessage }}</span>
|
||||
</div>
|
||||
|
||||
<div id="session-container" *ngIf="joinSessionClicked && isSessionAlive && !error">
|
||||
<div id="session-container" *ngIf="(joinSessionClicked || !showPrejoin) && participantReady && !error">
|
||||
<ov-session [tokens]="_tokens">
|
||||
<ng-template #toolbar>
|
||||
<ng-container *ngIf="openviduAngularToolbarTemplate">
|
||||
|
|
|
@ -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<any>();
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]'
|
||||
})
|
||||
|
|
|
@ -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();;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ export class OpenViduAngularConfigService {
|
|||
|
||||
minimal = <BehaviorSubject<boolean>>new BehaviorSubject(false);
|
||||
minimalObs: Observable<boolean>;
|
||||
prejoin = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
prejoinObs: Observable<boolean>;
|
||||
|
||||
videoMuted = <BehaviorSubject<boolean>>new BehaviorSubject(false);
|
||||
videoMutedObs: Observable<boolean>;
|
||||
audioMuted = <BehaviorSubject<boolean>>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";
|
||||
|
|
Loading…
Reference in New Issue