openvidu-components: Allowed meeting customization

Added attribute directives for allowing the app customization
pull/707/head
csantosm 2022-03-07 15:50:27 +01:00
parent 4cb959ac83
commit c6e84cb5da
24 changed files with 876 additions and 165 deletions

View File

@ -1,6 +1,6 @@
<div id="layout" class="layout"> <div id="layout" class="layout">
<div <div
class="OT_root OT_publisher" class="OT_root OT_publisher ovStream"
*ngFor="let stream of localParticipant | streams" *ngFor="let stream of localParticipant | streams"
[ngClass]="{ OV_big: stream.videoEnlarged }" [ngClass]="{ OV_big: stream.videoEnlarged }"
> >
@ -9,7 +9,7 @@
<div <div
*ngFor="let stream of remoteParticipants | streams" *ngFor="let stream of remoteParticipants | streams"
class="OT_root OT_publisher" class="OT_root OT_publisher ovStream"
id="remote-participant" id="remote-participant"
[ngClass]="{ OV_big: stream.videoEnlarged }" [ngClass]="{ OV_big: stream.videoEnlarged }"
> >

View File

@ -3,7 +3,7 @@ import { Subscription } from 'rxjs';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
import { ParticipantAbstractModel } from '../../models/participant.model'; import { ParticipantAbstractModel } from '../../models/participant.model';
import { LayoutService } from '../../services/layout/layout.service'; import { LayoutService } from '../../services/layout/layout.service';
import { StreamDirective } from '../../directives/openvidu-angular.directive'; import { StreamDirective } from '../../directives/template/openvidu-angular.directive';
@Component({ @Component({
selector: 'ov-layout', selector: 'ov-layout',

View File

@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core';
import { skip, Subscription } from 'rxjs'; import { skip, Subscription } from 'rxjs';
import { ChatPanelDirective, ParticipantsPanelDirective } from '../../directives/openvidu-angular.directive'; import { ChatPanelDirective, ParticipantsPanelDirective } from '../../directives/template/openvidu-angular.directive';
import { MenuType } from '../../models/menu.model'; import { MenuType } from '../../models/menu.model';
import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.service'; import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.service';

View File

@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, On
import { ParticipantAbstractModel } from '../../../../models/participant.model'; import { ParticipantAbstractModel } from '../../../../models/participant.model';
import { ParticipantService } from '../../../../services/participant/participant.service'; import { ParticipantService } from '../../../../services/participant/participant.service';
import { SidenavMenuService } from '../../../..//services/sidenav-menu/sidenav-menu.service'; import { SidenavMenuService } from '../../../..//services/sidenav-menu/sidenav-menu.service';
import { ParticipantPanelItemDirective } from '../../../../directives/openvidu-angular.directive'; import { ParticipantPanelItemDirective } from '../../../../directives/template/openvidu-angular.directive';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@Component({ @Component({

View File

@ -2,7 +2,7 @@
<div fxFlex.gt-sm="65%" fxFlex.lt-md="55%" fxLayoutAlign="center center"> <div fxFlex.gt-sm="65%" fxFlex.lt-md="55%" fxLayoutAlign="center center">
<ov-layout> <ov-layout>
<ng-template #stream let-stream> <ng-template #stream let-stream>
<ov-stream [stream]="stream" [showNickname]="false" [showSettings]="false"></ov-stream> <ov-stream [stream]="stream" [displayParticipantName]="false" [settingsButton]="false"></ov-stream>
</ng-template> </ng-template>
</ov-layout> </ov-layout>
</div> </div>

View File

@ -19,7 +19,7 @@
</mat-sidenav-content> </mat-sidenav-content>
</mat-sidenav-container> </mat-sidenav-container>
<div id="footer-container"> <div id="footer-container" class="ovToolbar">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container> <ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@
[id]="'container-' + this._stream.streamManager?.stream?.streamId" [id]="'container-' + this._stream.streamManager?.stream?.streamId"
#streamContainer #streamContainer
> >
<div class="nickname" [class.fullscreen]="isFullscreen" *ngIf="showNickname"> <div *ngIf="!isMinimal && showNickname" class="nickname" [class.fullscreen]="isFullscreen">
<div (click)="toggleNicknameForm()" class="nicknameContainer" selected *ngIf="!toggleNickname"> <div (click)="toggleNicknameForm()" class="nicknameContainer" selected *ngIf="!toggleNickname">
<span id="nickname" *ngIf="this._stream.type === 'CAMERA'">{{ this._stream.participant.nickname }}</span> <span id="nickname" *ngIf="this._stream.type === 'CAMERA'">{{ this._stream.participant.nickname }}</span>
<span id="nickname" *ngIf="this._stream.type === 'SCREEN'">{{ this._stream.participant.nickname }}_SCREEN</span> <span id="nickname" *ngIf="this._stream.type === 'SCREEN'">{{ this._stream.participant.nickname }}_SCREEN</span>
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div id="audio-wave-container" *ngIf="showAudioDetection && _stream.type === 'CAMERA'"> <div *ngIf="!isMinimal && showAudioDetection && _stream.type === 'CAMERA'" id="audio-wave-container">
<ov-audio-wave [streamManager]="_stream.streamManager"></ov-audio-wave> <ov-audio-wave [streamManager]="_stream.streamManager"></ov-audio-wave>
</div> </div>
@ -44,7 +44,7 @@
</button> </button>
</div> </div>
<div class="videoButtons" *ngIf="showSettings"> <div *ngIf="!isMinimal && showSettingsButton" class="videoButtons">
<button mat-icon-button (click)="toggleVideoMenu($event)" matTooltip="Settings" aria-label="Video settings menu"> <button mat-icon-button (click)="toggleVideoMenu($event)" matTooltip="Settings" aria-label="Video settings menu">
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
</button> </button>

View File

@ -1,4 +1,5 @@
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { Subscription } from 'rxjs';
import { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu'; import { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu';
import { VideoSizeIcon } from '../../models/icon.model'; import { VideoSizeIcon } from '../../models/icon.model';
import { ScreenType, VideoType } from '../../models/video-type.model'; import { ScreenType, VideoType } from '../../models/video-type.model';
@ -11,6 +12,7 @@ import { Signal } from '../../models/signal.model';
import { PublisherProperties } from 'openvidu-browser'; import { PublisherProperties } from 'openvidu-browser';
import { StreamModel } from '../../models/participant.model'; import { StreamModel } from '../../models/participant.model';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
@Component({ @Component({
selector: 'ov-stream', selector: 'ov-stream',
@ -18,19 +20,27 @@ import { ParticipantService } from '../../services/participant/participant.servi
styleUrls: ['./stream.component.css'] styleUrls: ['./stream.component.css']
}) })
export class StreamComponent implements OnInit { export class StreamComponent implements OnInit {
@ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger;
@ViewChild('menu') menu: MatMenuPanel;
videoSizeIconEnum = VideoSizeIcon; videoSizeIconEnum = VideoSizeIcon;
videoTypeEnum = VideoType; videoTypeEnum = VideoType;
videoSizeIcon: VideoSizeIcon = VideoSizeIcon.BIG; videoSizeIcon: VideoSizeIcon = VideoSizeIcon.BIG;
toggleNickname: boolean; toggleNickname: boolean;
_stream: StreamModel; _stream: StreamModel;
nickname: string; nickname: string;
private _streamContainer: ElementRef;
@ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger;
@ViewChild('menu') menu: MatMenuPanel;
@Input() showNickname: boolean = true; isMinimal: boolean = false;
@Input() showAudioDetection: boolean = true; showNickname: boolean = true;
@Input() showSettings: boolean = true; showAudioDetection: boolean = true;
showSettingsButton: boolean = true;
private _streamContainer: ElementRef;
private minimalSub: Subscription;
private displayParticipantNameSub: Subscription;
private displayAudioDetectionSub: Subscription;
private settingsButtonSub: Subscription;
constructor( constructor(
protected documentService: DocumentService, protected documentService: DocumentService,
@ -38,7 +48,8 @@ export class StreamComponent implements OnInit {
protected layoutService: LayoutService, protected layoutService: LayoutService,
protected participantService: ParticipantService, protected participantService: ParticipantService,
protected storageService: StorageService, protected storageService: StorageService,
protected cdkSrv: CdkOverlayService protected cdkSrv: CdkOverlayService,
private libService: OpenViduAngularConfigService
) {} ) {}
@ViewChild('streamContainer', { static: false, read: ElementRef }) @ViewChild('streamContainer', { static: false, read: ElementRef })
@ -57,7 +68,7 @@ export class StreamComponent implements OnInit {
set stream(stream: StreamModel) { set stream(stream: StreamModel) {
this._stream = stream; this._stream = stream;
this.checkVideoEnlarged(); this.checkVideoEnlarged();
if(this._stream.participant) { if (this._stream.participant) {
this.nickname = this._stream.participant.nickname; this.nickname = this._stream.participant.nickname;
} }
} }
@ -70,10 +81,14 @@ export class StreamComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.subscribeToStreamDirectives();
} }
ngOnDestroy() { ngOnDestroy() {
this.cdkSrv.setSelector('body'); this.cdkSrv.setSelector('body');
if (this.settingsButtonSub) this.settingsButtonSub.unsubscribe();
if (this.displayAudioDetectionSub) this.displayAudioDetectionSub.unsubscribe();
if (this.displayParticipantNameSub) this.displayParticipantNameSub.unsubscribe();
} }
toggleVideoEnlarged() { toggleVideoEnlarged() {
@ -98,7 +113,6 @@ export class StreamComponent implements OnInit {
toggleSound() { toggleSound() {
this._stream.participant.setMutedForcibly(!this._stream.participant.isMutedForcibly); this._stream.participant.setMutedForcibly(!this._stream.participant.isMutedForcibly);
} }
toggleNicknameForm() { toggleNicknameForm() {
@ -109,7 +123,7 @@ export class StreamComponent implements OnInit {
updateNickname(event) { updateNickname(event) {
if (event?.keyCode === 13 || event?.type === 'focusout') { if (event?.keyCode === 13 || event?.type === 'focusout') {
if(!!this.nickname){ if (!!this.nickname) {
this.participantService.setMyNickname(this.nickname); this.participantService.setMyNickname(this.nickname);
this.storageService.setNickname(this.nickname); this.storageService.setNickname(this.nickname);
this.openviduService.sendSignal(Signal.NICKNAME_CHANGED, undefined, { clientData: this.nickname }); this.openviduService.sendSignal(Signal.NICKNAME_CHANGED, undefined, { clientData: this.nickname });
@ -128,7 +142,26 @@ export class StreamComponent implements OnInit {
await this.openviduService.replaceTrack(VideoType.SCREEN, properties); await this.openviduService.replaceTrack(VideoType.SCREEN, properties);
} }
protected checkVideoEnlarged() { private checkVideoEnlarged() {
this.videoSizeIcon = this._stream.videoEnlarged ? VideoSizeIcon.NORMAL : VideoSizeIcon.BIG; this.videoSizeIcon = this._stream.videoEnlarged ? VideoSizeIcon.NORMAL : VideoSizeIcon.BIG;
} }
private subscribeToStreamDirectives() {
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
this.isMinimal = value;
});
this.displayParticipantNameSub = this.libService.displayParticipantNameObs.subscribe((value: boolean) => {
this.showNickname = value;
// this.cd.markForCheck();
});
this.displayAudioDetectionSub = this.libService.displayAudioDetectionObs.subscribe((value: boolean) => {
this.showAudioDetection = value;
// this.cd.markForCheck();
});
this.settingsButtonSub = this.libService.settingsButtonObs.subscribe((value: boolean) => {
this.showSettingsButton = value;
// this.cd.markForCheck();
});
}
} }

View File

@ -14,6 +14,9 @@
display: flex; display: flex;
align-items: center; align-items: center;
} }
#media-buttons-container {
max-height: 100%;
}
#media-buttons-container > *, ::ng-deep #media-buttons-container > * { #media-buttons-container > *, ::ng-deep #media-buttons-container > * {
width: 40px; width: 40px;

View File

@ -1,8 +1,8 @@
<mat-toolbar id="toolbar" role="heading" fxLayout fxLayoutAlign="center" fxLayoutGap="10px"> <mat-toolbar id="toolbar" role="heading" fxLayout fxLayoutAlign="center" fxLayoutGap="10px">
<div fxFlex="20%" fxLayoutAlign="start center"> <div fxFlex="20%" fxLayoutAlign="start center">
<div id="img-container"> <div id="img-container">
<img id="branding-logo" src='assets/images/openvidu_globe.png'/> <img *ngIf="!isMinimal && showLogo" id="branding-logo" src="assets/images/ov_company_logo.png" ovImage />
<span id="session-title" *ngIf="session && session.sessionId">{{ session.sessionId }}</span> <span id="session-title" *ngIf="!isMinimal && session && session.sessionId && showSessionName">{{ session.sessionId }}</span>
</div> </div>
</div> </div>
<div fxFlex="60%" fxFlexOrder="2" fxLayoutAlign="center center" id="media-buttons-container"> <div fxFlex="60%" fxFlexOrder="2" fxLayoutAlign="center center" id="media-buttons-container">
@ -32,8 +32,9 @@
<!-- Screenshare button --> <!-- Screenshare button -->
<button <button
id="navScreenButton"
mat-icon-button mat-icon-button
*ngIf="!isMinimal && showScreenshareButton"
id="navScreenButton"
(click)="toggleScreenShare()" (click)="toggleScreenShare()"
[disabled]="isConnectionLost" [disabled]="isConnectionLost"
[class.active-btn]="isScreenShareActive" [class.active-btn]="isScreenShareActive"
@ -43,7 +44,13 @@
</button> </button>
<!-- Fullscreen button --> <!-- Fullscreen button -->
<button mat-icon-button (click)="toggleFullscreen()" [disabled]="isConnectionLost" [class.active-btn]="isFullscreenActive"> <button
mat-icon-button
*ngIf="!isMinimal && showFullscreenButton"
(click)="toggleFullscreen()"
[disabled]="isConnectionLost"
[class.active-btn]="isFullscreenActive"
>
<mat-icon *ngIf="isFullscreenActive" matTooltip="Exit Fullscreen">fullscreen_exit</mat-icon> <mat-icon *ngIf="isFullscreenActive" matTooltip="Exit Fullscreen">fullscreen_exit</mat-icon>
<mat-icon *ngIf="!isFullscreenActive" matTooltip="Fullscreen">fullscreen</mat-icon> <mat-icon *ngIf="!isFullscreenActive" matTooltip="Fullscreen">fullscreen</mat-icon>
</button> </button>
@ -52,7 +59,7 @@
<ng-content select="[toolbar-btn]"></ng-content> <ng-content select="[toolbar-btn]"></ng-content>
<!-- Leave session button --> <!-- Leave session button -->
<button mat-icon-button (click)="leaveSession()" id="leave-btn"> <button mat-icon-button *ngIf="showLeaveButton" (click)="leaveSession()" id="leave-btn">
<mat-icon matTooltip="Leave the session">call_end</mat-icon> <mat-icon matTooltip="Leave the session">call_end</mat-icon>
</button> </button>
</div> </div>
@ -60,6 +67,7 @@
<!-- Default participants button --> <!-- Default participants button -->
<button <button
mat-icon-button mat-icon-button
*ngIf="!isMinimal && showParticipantsPanelButton"
matTooltip="Show articipants" matTooltip="Show articipants"
(click)="toggleMenu('participants')" (click)="toggleMenu('participants')"
[disabled]="isConnectionLost" [disabled]="isConnectionLost"
@ -68,14 +76,10 @@
<mat-icon>people</mat-icon> <mat-icon>people</mat-icon>
</button> </button>
<div #customMenuButton>
<ng-content select="[menu-button]"></ng-content>
</div>
<!-- Default chat button --> <!-- Default chat button -->
<button <button
mat-icon-button mat-icon-button
*ngIf="!customMenuButton.innerHTML" *ngIf="!isMinimal && showChatPanelButton"
(click)="toggleMenu('chat')" (click)="toggleMenu('chat')"
[disabled]="isConnectionLost" [disabled]="isConnectionLost"
[class.active-btn]="isChatOpened" [class.active-btn]="isChatOpened"

View File

@ -26,6 +26,7 @@ import { DeviceService } from '../../services/device/device.service';
import { ChatMessage } from '../../models/chat.model'; import { ChatMessage } from '../../models/chat.model';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
import { MenuType } from '../../models/menu.model'; import { MenuType } from '../../models/menu.model';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
@Component({ @Component({
selector: 'ov-toolbar', selector: 'ov-toolbar',
@ -55,12 +56,48 @@ export class ToolbarComponent implements OnInit, OnDestroy {
isChatOpened: boolean = false; isChatOpened: boolean = false;
isParticipantsOpened: boolean = false; isParticipantsOpened: boolean = false;
protected log: ILogger; isMinimal: boolean = false;
protected menuTogglingSubscription: Subscription; showScreenshareButton = true;
protected chatMessagesSubscription: Subscription; showFullscreenButton: boolean = true;
protected localParticipantSubscription: Subscription; showLeaveButton: boolean = true;
showParticipantsPanelButton: boolean = true;
showChatPanelButton: boolean = true;
showLogo: boolean = true;
showSessionName: boolean = true;
private log: ILogger;
private minimalSub: Subscription;
private menuTogglingSubscription: Subscription;
private chatMessagesSubscription: Subscription;
private localParticipantSubscription: Subscription;
private screenshareButtonSub: Subscription;
private fullscreenButtonSub: Subscription;
private leaveButtonSub: Subscription;
private participantsPanelButtonSub: Subscription;
private chatPanelButtonSub: Subscription;
private displayLogoSub: Subscription;
private displaySessionNameSub: Subscription;
private currentWindowHeight = window.innerHeight; private currentWindowHeight = window.innerHeight;
@HostListener('window:resize', ['$event'])
sizeChange(event) {
if (this.currentWindowHeight >= window.innerHeight) {
// The user has exit the fullscreen mode
this.isFullscreenActive = false;
this.currentWindowHeight = window.innerHeight;
}
}
@HostListener('document:keydown', ['$event'])
keyDown(event: KeyboardEvent) {
if (event.key === 'F11') {
event.preventDefault();
this.toggleFullscreen();
this.currentWindowHeight = window.innerHeight;
return false;
}
}
constructor( constructor(
protected documentService: DocumentService, protected documentService: DocumentService,
protected chatService: ChatService, protected chatService: ChatService,
@ -71,43 +108,15 @@ export class ToolbarComponent implements OnInit, OnDestroy {
protected oVDevicesService: DeviceService, protected oVDevicesService: DeviceService,
protected actionService: ActionService, protected actionService: ActionService,
protected loggerSrv: LoggerService, protected loggerSrv: LoggerService,
private cd: ChangeDetectorRef private cd: ChangeDetectorRef,
private libService: OpenViduAngularConfigService
) { ) {
this.log = this.loggerSrv.get('ToolbarComponent'); this.log = this.loggerSrv.get('ToolbarComponent');
} }
ngOnDestroy(): void {
if (this.menuTogglingSubscription) {
this.menuTogglingSubscription.unsubscribe();
}
if (this.chatMessagesSubscription) {
this.chatMessagesSubscription.unsubscribe();
}
if (this.localParticipantSubscription) {
this.localParticipantSubscription.unsubscribe();
}
}
@HostListener('window:resize', ['$event'])
sizeChange(event) {
if(this.currentWindowHeight >= window.innerHeight) {
// The user has exit the fullscreen mode
this.isFullscreenActive = false;
this.currentWindowHeight = window.innerHeight;
}
}
@HostListener('document:keydown', ['$event'])
keyDown(event: KeyboardEvent) {
if(event.key === 'F11'){
event.preventDefault();
this.toggleFullscreen();
this.currentWindowHeight = window.innerHeight;
return false;
}
}
async ngOnInit() { async ngOnInit() {
this.subscribeToToolbarDirectives();
await this.oVDevicesService.initializeDevices(); await this.oVDevicesService.initializeDevices();
this.hasVideoDevices = this.oVDevicesService.hasVideoDeviceAvailable(); this.hasVideoDevices = this.oVDevicesService.hasVideoDeviceAvailable();
this.hasAudioDevices = this.oVDevicesService.hasAudioDeviceAvailable(); this.hasAudioDevices = this.oVDevicesService.hasAudioDeviceAvailable();
@ -119,6 +128,19 @@ export class ToolbarComponent implements OnInit, OnDestroy {
this.subscribeToChatMessages(); this.subscribeToChatMessages();
} }
ngOnDestroy(): void {
if (this.menuTogglingSubscription) this.menuTogglingSubscription.unsubscribe();
if (this.chatMessagesSubscription) this.chatMessagesSubscription.unsubscribe();
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe();
if (this.fullscreenButtonSub) this.fullscreenButtonSub.unsubscribe();
if (this.leaveButtonSub) this.leaveButtonSub.unsubscribe();
if (this.participantsPanelButtonSub) this.participantsPanelButtonSub.unsubscribe();
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
if (this.displaySessionNameSub) this.displaySessionNameSub.unsubscribe();
}
toggleMicrophone() { toggleMicrophone() {
this.onMicClicked.emit(); this.onMicClicked.emit();
@ -297,4 +319,39 @@ export class ToolbarComponent implements OnInit, OnDestroy {
this.cd.markForCheck(); this.cd.markForCheck();
}); });
} }
private subscribeToToolbarDirectives() {
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
this.isMinimal = value;
this.cd.markForCheck();
});
this.screenshareButtonSub = this.libService.screenshareButtonObs.subscribe((value: boolean) => {
this.showScreenshareButton = value;
this.cd.markForCheck();
});
this.fullscreenButtonSub = this.libService.fullscreenButtonObs.subscribe((value: boolean) => {
this.showFullscreenButton = value;
this.cd.markForCheck();
});
this.leaveButtonSub = this.libService.leaveButtonObs.subscribe((value: boolean) => {
this.showLeaveButton = value;
this.cd.markForCheck();
});
this.chatPanelButtonSub = this.libService.chatPanelButtonObs.subscribe((value: boolean) => {
this.showChatPanelButton = value;
this.cd.markForCheck();
});
this.participantsPanelButtonSub = this.libService.participantsPanelButtonObs.subscribe((value: boolean) => {
this.showParticipantsPanelButton = value;
this.cd.markForCheck();
});
this.displayLogoSub = this.libService.displayLogoObs.subscribe((value: boolean) => {
this.showLogo = value;
this.cd.markForCheck();
});
this.displaySessionNameSub = this.libService.displaySessionNameObs.subscribe((value: boolean) => {
this.showSessionName = value;
this.cd.markForCheck();
});
}
} }

View File

@ -7,7 +7,7 @@ import {
ParticipantsPanelDirective, ParticipantsPanelDirective,
StreamDirective, StreamDirective,
ToolbarDirective ToolbarDirective
} from '../../directives/openvidu-angular.directive'; } from '../../directives/template/openvidu-angular.directive';
import { ILogger } from '../../models/logger.model'; import { ILogger } from '../../models/logger.model';
import { LoggerService } from '../../services/logger/logger.service'; import { LoggerService } from '../../services/logger/logger.service';
@ -17,13 +17,16 @@ import { LoggerService } from '../../services/logger/logger.service';
styleUrls: ['./videoconference.component.css'] styleUrls: ['./videoconference.component.css']
}) })
export class VideoconferenceComponent implements OnInit, AfterViewInit { export class VideoconferenceComponent implements OnInit, AfterViewInit {
//Toolbar // *** Toolbar ***
@ContentChild(ToolbarDirective) externalToolbar: ToolbarDirective; @ContentChild(ToolbarDirective) externalToolbar: ToolbarDirective;
// Panels
// *** Panels ***
@ContentChild(PanelDirective) externalPanel: PanelDirective; @ContentChild(PanelDirective) externalPanel: PanelDirective;
@ContentChild(ChatPanelDirective) externalChatPanel: ChatPanelDirective; @ContentChild(ChatPanelDirective) externalChatPanel: ChatPanelDirective;
@ContentChild(ParticipantsPanelDirective) externalParticipantsPanel: ParticipantsPanelDirective; @ContentChild(ParticipantsPanelDirective) externalParticipantsPanel: ParticipantsPanelDirective;
@ContentChild(ParticipantPanelItemDirective) externalParticipantPanelItem: ParticipantPanelItemDirective; @ContentChild(ParticipantPanelItemDirective) externalParticipantPanelItem: ParticipantPanelItemDirective;
// *** Layout ***
@ContentChild(LayoutDirective) externalLayout: LayoutDirective; @ContentChild(LayoutDirective) externalLayout: LayoutDirective;
@ContentChild(StreamDirective) externalStream: StreamDirective; @ContentChild(StreamDirective) externalStream: StreamDirective;
@ -43,8 +46,9 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit {
openviduAngularLayoutTemplate: TemplateRef<any>; openviduAngularLayoutTemplate: TemplateRef<any>;
openviduAngularStreamTemplate: TemplateRef<any>; openviduAngularStreamTemplate: TemplateRef<any>;
// *** Parameters ***
@Input() sessionName: string; @Input() sessionName: string;
@Input() userName: string; @Input() participantName: string;
@Input() @Input()
set tokens(tokens: { webcam: string; screen: string }) { set tokens(tokens: { webcam: string; screen: string }) {
@ -63,8 +67,20 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit {
} }
} }
@Output() onJoinClicked = new EventEmitter<any>(); // *** Events ***
@Output() onCloseClicked = new EventEmitter<any>();
// Event sent when user click on the join button in pre-join page
@Output() onJoinSessionClicked = new EventEmitter<any>();
// Event sent when participant has joined the session
@Output() onParticipantJoined = new EventEmitter<any>();
// Event sent when participant has left the session
@Output() onParticipantLeft = new EventEmitter<any>();
// Event sent when session has been created
@Output() onSessionCreated = new EventEmitter<any>();
joinSessionClicked: boolean = false; joinSessionClicked: boolean = false;
// closeClicked: boolean = false; // closeClicked: boolean = false;
@ -140,7 +156,7 @@ export class VideoconferenceComponent implements OnInit, AfterViewInit {
async _onJoinClicked() { async _onJoinClicked() {
this.joinSessionClicked = true; this.joinSessionClicked = true;
this.onJoinClicked.emit(); this.onJoinSessionClicked.emit();
} }
// onLeaveSessionClicked() { // onLeaveSessionClicked() {
// this.isSessionAlive = false; // this.isSessionAlive = false;

View File

@ -0,0 +1,50 @@
import { NgModule } from '@angular/core';
import {
StreamDisplayParticipantNameDirective,
StreamDisplayAudioDetectionDirective,
StreamSettingsButtonDirective
} from './stream.directive';
import {
ToolbarScreenshareButtonDirective,
ToolbarFullscreenButtonDirective,
ToolbarLeaveButtonDirective,
ToolbarParticipantsPanelButtonDirective,
ToolbarChatPanelButtonDirective,
ToolbarDisplaySessionNameDirective,
ToolbarDisplayLogoDirective
} from './toolbar.directive';
import { AudioMutedDirective, MinimalDirective, VideoMutedDirective } from './videoconference.directive';
@NgModule({
declarations: [
MinimalDirective,
VideoMutedDirective,
AudioMutedDirective,
ToolbarScreenshareButtonDirective,
ToolbarFullscreenButtonDirective,
ToolbarLeaveButtonDirective,
ToolbarParticipantsPanelButtonDirective,
ToolbarChatPanelButtonDirective,
ToolbarDisplaySessionNameDirective,
ToolbarDisplayLogoDirective,
StreamDisplayParticipantNameDirective,
StreamDisplayAudioDetectionDirective,
StreamSettingsButtonDirective,
],
exports: [
MinimalDirective,
VideoMutedDirective,
AudioMutedDirective,
ToolbarScreenshareButtonDirective,
ToolbarFullscreenButtonDirective,
ToolbarLeaveButtonDirective,
ToolbarParticipantsPanelButtonDirective,
ToolbarChatPanelButtonDirective,
ToolbarDisplaySessionNameDirective,
ToolbarDisplayLogoDirective,
StreamDisplayParticipantNameDirective,
StreamDisplayAudioDetectionDirective,
StreamSettingsButtonDirective
]
})
export class ApiDirectiveModule {}

View File

@ -0,0 +1,131 @@
import { AfterViewInit, Directive, ElementRef, Input } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
const VIDEOCONFERENCE_COMPONENT_NAME = 'ov-videoconference';
const OV_STREAM_CLASS = 'ovStream';
@Directive({
selector: 'ov-videoconference[streamDisplayParticipantName], [displayParticipantName]'
})
export class StreamDisplayParticipantNameDirective implements AfterViewInit {
@Input() set streamDisplayParticipantName(value: boolean) {
this.displayParticipantNameValue = value;
this.update(this.displayParticipantNameValue);
}
@Input() set displayParticipantName(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_STREAM_CLASS);
if (isExternalComponentInput) {
this.displayParticipantNameValue = value;
this.update(this.displayParticipantNameValue);
}
}
displayParticipantNameValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_STREAM_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.displayParticipantNameValue);
}
}
update(value: boolean) {
if (this.libService.displayParticipantName.getValue() !== value) {
this.libService.displayParticipantName.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[streamDisplayAudioDetection], [displayAudioDetection]'
})
export class StreamDisplayAudioDetectionDirective implements AfterViewInit {
@Input() set streamDisplayAudioDetection(value: boolean) {
this.displayAudioDetectionValue = value;
this.update(this.displayAudioDetectionValue);
}
@Input() set displayAudioDetection(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_STREAM_CLASS);
if (isExternalComponentInput) {
this.displayAudioDetectionValue = value;
this.update(this.displayAudioDetectionValue);
}
}
displayAudioDetectionValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_STREAM_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.displayAudioDetectionValue);
}
}
update(value: boolean) {
if (this.libService.displayAudioDetection.getValue() !== value) {
this.libService.displayAudioDetection.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[streamSettingsButton], [settingsButton]'
})
export class StreamSettingsButtonDirective implements AfterViewInit {
@Input() set streamSettingsButton(value: boolean) {
this.settingsValue = value;
this.update(this.settingsValue);
}
@Input() set settingsButton(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_STREAM_CLASS);
if (isExternalComponentInput) {
this.settingsValue = value;
this.update(this.settingsValue);
}
}
settingsValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_STREAM_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.settingsValue);
}
}
update(value: boolean) {
if (this.libService.settingsButton.getValue() !== value) {
this.libService.settingsButton.next(value);
}
}
}

View File

@ -0,0 +1,300 @@
import { AfterViewInit, Directive, ElementRef, Input } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
const VIDEOCONFERENCE_COMPONENT_NAME = 'ov-videoconference';
const OV_TOOLBAR_CLASS = 'ovToolbar';
@Directive({
selector: 'ov-videoconference[toolbarScreenshareButton], [screenshareButton]'
})
export class ToolbarScreenshareButtonDirective implements AfterViewInit {
@Input() set toolbarScreenshareButton(value: boolean) {
this.screenshareValue = value;
this.update(this.screenshareValue);
}
@Input() set screenshareButton(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.screenshareValue = value;
this.update(this.screenshareValue);
}
}
screenshareValue: boolean = true;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// We need to distinguish where the directive is being used
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.screenshareValue);
}
}
update(value: boolean) {
if (this.libService.screenshareButton.getValue() !== value) {
this.libService.screenshareButton.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[toolbarFullscreenButton], [fullscreenButton]'
})
export class ToolbarFullscreenButtonDirective implements AfterViewInit {
@Input() set toolbarFullscreenButton(value: boolean) {
this.fullscreenValue = value;
this.update(this.fullscreenValue);
}
@Input() set fullscreenButton(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.fullscreenValue = value;
this.update(this.fullscreenValue);
}
}
fullscreenValue: boolean = true;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// We need to distinguish where the directive is being used
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.fullscreenValue);
}
}
update(value: boolean) {
if (this.libService.fullscreenButton.getValue() !== value) {
this.libService.fullscreenButton.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[toolbarLeaveButton], [leaveButton]'
})
export class ToolbarLeaveButtonDirective implements AfterViewInit {
@Input() set toolbarLeaveButton(value: boolean) {
this.leaveValue = value;
this.update(this.leaveValue);
}
@Input() set leaveButton(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.leaveValue = value;
this.update(this.leaveValue);
}
}
leaveValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.leaveValue);
}
}
update(value: boolean) {
if (this.libService.leaveButton.getValue() !== value) {
this.libService.leaveButton.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[toolbarParticipantsPanelButton], [participantsPanelButton]'
})
export class ToolbarParticipantsPanelButtonDirective implements AfterViewInit {
@Input() set toolbarParticipantsPanelButton(value: boolean) {
this.participantsPanelValue = value;
this.update(this.participantsPanelValue);
}
@Input() set participantsPanelButton(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.participantsPanelValue = value;
this.update(this.participantsPanelValue);
}
}
participantsPanelValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.participantsPanelValue);
}
}
update(value: boolean) {
if (this.libService.participantsPanelButton.getValue() !== value) {
this.libService.participantsPanelButton.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[toolbarChatPanelButton], [chatPanelButton]'
})
export class ToolbarChatPanelButtonDirective implements AfterViewInit {
@Input() set toolbarChatPanelButton(value: boolean) {
this.toolbarChatPanelValue = value;
this.update(this.toolbarChatPanelValue);
}
@Input() set chatPanelButton(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.toolbarChatPanelValue = value;
this.update(this.toolbarChatPanelValue);
}
}
toolbarChatPanelValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.toolbarChatPanelValue);
}
}
update(value: boolean) {
if (this.libService.chatPanelButton.getValue() !== value) {
this.libService.chatPanelButton.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[toolbarDisplaySessionName], [displaySessionName]'
})
export class ToolbarDisplaySessionNameDirective implements AfterViewInit {
@Input() set toolbarDisplaySessionName(value: boolean) {
this.displaySessionValue = value;
this.update(this.displaySessionValue);
}
@Input() set displaySessionName(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.displaySessionValue = value;
this.update(this.displaySessionValue);
}
}
displaySessionValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.displaySessionValue);
}
}
update(value: boolean) {
if (this.libService.displaySessionName.getValue() !== value) {
this.libService.displaySessionName.next(value);
}
}
}
@Directive({
selector: 'ov-videoconference[toolbarDisplayLogo], [displayLogo]'
})
export class ToolbarDisplayLogoDirective implements AfterViewInit {
@Input() set toolbarDisplayLogo(value: boolean) {
this.displayLogoValue = value;
this.update(this.displayLogoValue);
}
@Input() set displayLogo(value: boolean) {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isExternalComponentInput) {
this.displayLogoValue = value;
this.update(this.displayLogoValue);
}
}
displayLogoValue: boolean;
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
const element = <HTMLElement>this.elementRef.nativeElement;
// Checking if 'screenButton' attribute is in the 'ov-videoconference' element
const isGlobalInput = element.localName === VIDEOCONFERENCE_COMPONENT_NAME;
// Checking if element is injected inside of an element with ovToolbar class
const isExternalComponentInput = element.parentElement?.classList.contains(OV_TOOLBAR_CLASS);
if (isGlobalInput || isExternalComponentInput) {
this.update(this.displayLogoValue);
}
}
update(value: boolean) {
if (this.libService.displayLogo.getValue() !== value) {
this.libService.displayLogo.next(value);
}
}
}

View File

@ -0,0 +1,32 @@
import { Directive, Input, ElementRef } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
@Directive({
selector: 'ov-videoconference[minimal]'
})
export class MinimalDirective {
@Input() set minimal(value: boolean) {
this.libService.minimal.next(value);
}
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
}
@Directive({
selector: 'ov-videoconference[videoMuted]'
})
export class VideoMutedDirective {
@Input() set videoMuted(value: boolean) {
this.libService.videoMuted.next(value);
}
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
}
@Directive({
selector: 'ov-videoconference[audioMuted]'
})
export class AudioMutedDirective {
@Input() set audioMuted(value: boolean) {
this.libService.audioMuted.next(value);
}
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
}

View File

@ -1,8 +0,0 @@
import { OpenviduAngularDirective } from './openvidu-angular.directive';
describe('OpenviduAngularDirective', () => {
it('should create an instance', () => {
const directive = new OpenviduAngularDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -1,50 +0,0 @@
import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[ovToolbar]'
})
export class ToolbarDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({
selector: '[ovPanel]'
})
export class PanelDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({
selector: '[ovChatPanel]'
})
export class ChatPanelDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({
selector: '[ovParticipantsPanel]'
})
export class ParticipantsPanelDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({
selector: '[ovParticipantPanelItem]'
})
export class ParticipantPanelItemDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({
selector: '[ovLayout]'
})
export class LayoutDirective {
constructor(public template: TemplateRef<any>, public container: ViewContainerRef) {}
}
@Directive({
selector: '[ovStream]'
})
export class StreamDirective {
constructor(public template: TemplateRef<any>, public container: ViewContainerRef) {}
}

View File

@ -0,0 +1,35 @@
import { NgModule } from '@angular/core';
import {
ChatPanelDirective,
LayoutDirective,
OvImageDirective,
PanelDirective,
ParticipantPanelItemDirective,
ParticipantsPanelDirective,
StreamDirective,
ToolbarDirective
} from './openvidu-angular.directive';
@NgModule({
declarations: [
ChatPanelDirective,
LayoutDirective,
OvImageDirective,
PanelDirective,
ParticipantPanelItemDirective,
ParticipantsPanelDirective,
StreamDirective,
ToolbarDirective
],
exports: [
ChatPanelDirective,
LayoutDirective,
OvImageDirective,
PanelDirective,
ParticipantPanelItemDirective,
ParticipantsPanelDirective,
StreamDirective,
ToolbarDirective
]
})
export class OpenViduAngularDirectiveModule {}

View File

@ -60,16 +60,9 @@ import { PanelComponent } from './components/panel/panel.component';
import { AudioWaveComponent } from './components/audio-wave/audio-wave.component'; import { AudioWaveComponent } from './components/audio-wave/audio-wave.component';
import { PreJoinComponent } from './components/pre-join/pre-join.component'; import { PreJoinComponent } from './components/pre-join/pre-join.component';
import {
ChatPanelDirective,
LayoutDirective,
PanelDirective,
ParticipantPanelItemDirective,
ParticipantsPanelDirective,
StreamDirective,
ToolbarDirective
} from './directives/openvidu-angular.directive';
import { AvatarProfileComponent } from './components/avatar-profile/avatar-profile.component'; import { AvatarProfileComponent } from './components/avatar-profile/avatar-profile.component';
import { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.directive.module';
import { ApiDirectiveModule } from './directives/api/api.directive.module';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -89,15 +82,8 @@ import { AvatarProfileComponent } from './components/avatar-profile/avatar-profi
VideoconferenceComponent, VideoconferenceComponent,
AudioWaveComponent, AudioWaveComponent,
PanelComponent, PanelComponent,
ToolbarDirective, AvatarProfileComponent,
PanelDirective,
ChatPanelDirective,
ParticipantsPanelDirective,
ParticipantPanelItemDirective,
LayoutDirective,
StreamDirective,
PreJoinComponent, PreJoinComponent,
AvatarProfileComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -124,7 +110,9 @@ import { AvatarProfileComponent } from './components/avatar-profile/avatar-profi
FlexLayoutModule, FlexLayoutModule,
MatMenuModule, MatMenuModule,
MatDividerModule, MatDividerModule,
MatListModule MatListModule,
OpenViduAngularDirectiveModule,
ApiDirectiveModule
], ],
providers: [ providers: [
ActionService, ActionService,
@ -159,13 +147,8 @@ import { AvatarProfileComponent } from './components/avatar-profile/avatar-profi
ParticipantStreamsPipe, ParticipantStreamsPipe,
StreamTypesEnabledPipe, StreamTypesEnabledPipe,
CommonModule, CommonModule,
ToolbarDirective, OpenViduAngularDirectiveModule,
PanelDirective, ApiDirectiveModule
ChatPanelDirective,
ParticipantsPanelDirective,
ParticipantPanelItemDirective,
LayoutDirective,
StreamDirective
], ],
entryComponents: [DialogTemplateComponent] entryComponents: [DialogTemplateComponent]
}) })

View File

@ -1,17 +1,66 @@
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { OpenViduAngularConfig, ParticipantFactoryFunction } from '../../config/openvidu-angular.config'; import { OpenViduAngularConfig, ParticipantFactoryFunction } from '../../config/openvidu-angular.config';
// import { version } from '../../../../package.json'; // import { version } from '../../../../package.json';
@Injectable() @Injectable()
export class OpenViduAngularConfigService { export class OpenViduAngularConfigService {
private configuration: OpenViduAngularConfig; private configuration: OpenViduAngularConfig;
minimal = <BehaviorSubject<boolean>>new BehaviorSubject(false);
minimalObs: Observable<boolean>;
videoMuted = <BehaviorSubject<boolean>>new BehaviorSubject(false);
videoMutedObs: Observable<boolean>;
audioMuted = <BehaviorSubject<boolean>>new BehaviorSubject(false);
audioMutedObs: Observable<boolean>;
screenshareButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
screenshareButtonObs: Observable<boolean>;
fullscreenButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
fullscreenButtonObs: Observable<boolean>;
leaveButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
leaveButtonObs: Observable<boolean>;
participantsPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
participantsPanelButtonObs: Observable<boolean>;
chatPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
chatPanelButtonObs: Observable<boolean>;
displaySessionName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
displaySessionNameObs: Observable<boolean>;
displayLogo = <BehaviorSubject<boolean>>new BehaviorSubject(true);
displayLogoObs: Observable<boolean>;
displayParticipantName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
displayParticipantNameObs: Observable<boolean>;
displayAudioDetection = <BehaviorSubject<boolean>>new BehaviorSubject(true);
displayAudioDetectionObs: Observable<boolean>;
settingsButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
settingsButtonObs: Observable<boolean>;
constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) { constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) {
this.configuration = config; this.configuration = config;
console.log(this.configuration); console.log(this.configuration);
if(this.isProduction()) console.log('OpenVidu Angular Production Mode'); if(this.isProduction()) console.log('OpenVidu Angular Production Mode');
// console.log(version) this.minimalObs = this.minimal.asObservable();
this.videoMutedObs = this.videoMuted.asObservable();
this.audioMutedObs = this.audioMuted.asObservable();
//Toolbar observables
this.screenshareButtonObs = this.screenshareButton.asObservable();
this.fullscreenButtonObs = this.fullscreenButton.asObservable();
this.leaveButtonObs = this.leaveButton.asObservable();
this.participantsPanelButtonObs = this.participantsPanelButton.asObservable();
this.chatPanelButtonObs = this.chatPanelButton.asObservable();
this.displaySessionNameObs = this.displaySessionName.asObservable();
this.displayLogoObs = this.displayLogo.asObservable();
//Stream observables
this.displayParticipantNameObs = this.displayParticipantName.asObservable();
this.displayAudioDetectionObs = this.displayAudioDetection.asObservable();
this.settingsButtonObs = this.settingsButton.asObservable();
} }
getConfig(): OpenViduAngularConfig { getConfig(): OpenViduAngularConfig {

View File

@ -3,6 +3,7 @@ import { Device, OpenVidu, OpenViduError, OpenViduErrorName } from 'openvidu-bro
import { CameraType, DeviceType, CustomDevice } from '../../models/device.model'; import { CameraType, DeviceType, CustomDevice } 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 { LoggerService } from '../logger/logger.service'; import { LoggerService } from '../logger/logger.service';
import { PlatformService } from '../platform/platform.service'; import { PlatformService } from '../platform/platform.service';
@ -28,7 +29,12 @@ export class DeviceService {
private _isAudioMuted: boolean; private _isAudioMuted: boolean;
private deviceAccessDeniedError: boolean = false; private deviceAccessDeniedError: boolean = false;
constructor(private loggerSrv: LoggerService, private platformSrv: PlatformService, private storageSrv: StorageService) { constructor(
private loggerSrv: LoggerService,
private platformSrv: PlatformService,
private storageSrv: StorageService,
private libSrv: OpenViduAngularConfigService
) {
this.log = this.loggerSrv.get('DevicesService'); this.log = this.loggerSrv.get('DevicesService');
this.OV = new OpenVidu(); this.OV = new OpenVidu();
} }
@ -38,7 +44,6 @@ export class DeviceService {
} }
async initializeDevices() { async initializeDevices() {
try { try {
// Forcing media permissions request. // Forcing media permissions request.
// Sometimes, browser doens't launch the media permissions modal. // Sometimes, browser doens't launch the media permissions modal.
@ -54,8 +59,8 @@ export class DeviceService {
this.cameras = customDevices.cameras; this.cameras = customDevices.cameras;
this.microphones = customDevices.microphones; this.microphones = customDevices.microphones;
this._isVideoMuted = this.storageSrv.isVideoMuted(); this._isVideoMuted = this.storageSrv.isVideoMuted() || this.libSrv.videoMuted.getValue();
this._isAudioMuted = this.storageSrv.isAudioMuted(); this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue();;
this.log.d('Media devices', customDevices); this.log.d('Media devices', customDevices);
} }
@ -79,7 +84,7 @@ export class DeviceService {
if (!!storageMicrophone) { if (!!storageMicrophone) {
this.microphoneSelected = storageMicrophone; this.microphoneSelected = storageMicrophone;
} else if (customDevices.microphones.length > 0) { } else if (customDevices.microphones.length > 0) {
if(this.deviceAccessDeniedError && customDevices.microphones.length > 1){ if (this.deviceAccessDeniedError && customDevices.microphones.length > 1) {
// We assume that the default device is already in use // We assume that the default device is already in use
// Assign an alternative device with the aim of avoiding the DEVICE_ALREADY_IN_USE error // Assign an alternative device with the aim of avoiding the DEVICE_ALREADY_IN_USE error
this.microphoneSelected = customDevices.microphones[1]; this.microphoneSelected = customDevices.microphones[1];
@ -115,7 +120,7 @@ export class DeviceService {
if (!!storageCamera) { if (!!storageCamera) {
this.cameraSelected = storageCamera; this.cameraSelected = storageCamera;
} else if (customDevices.cameras.length > 0) { } else if (customDevices.cameras.length > 0) {
if(this.deviceAccessDeniedError && customDevices.cameras.length > 1){ if (this.deviceAccessDeniedError && customDevices.cameras.length > 1) {
// We assume that the default device is already in use // We assume that the default device is already in use
// Assign an alternative device with the aim of avoiding the DEVICE_ALREADY_IN_USE error // Assign an alternative device with the aim of avoiding the DEVICE_ALREADY_IN_USE error
this.cameraSelected = customDevices.cameras[1]; this.cameraSelected = customDevices.cameras[1];

View File

@ -46,4 +46,10 @@ export * from './lib/models/notification-options.model';
export * from './lib/pipes/participant.pipe'; export * from './lib/pipes/participant.pipe';
// Directives // Directives
export * from './lib/directives/openvidu-angular.directive'; export * from './lib/directives/api/api.directive.module';
export * from './lib/directives/template/openvidu-angular.directive.module';
export * from './lib/directives/template/openvidu-angular.directive';
export * from './lib/directives/api/toolbar.directive';
export * from './lib/directives/api/stream.directive';
export * from './lib/directives/api/videoconference.directive';