openvidu-components: Added openvidu-angular documentation

pull/707/head
csantosm 2022-03-23 13:48:17 +01:00
parent d81124150a
commit ff2dc6d86b
63 changed files with 5581 additions and 344 deletions

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@
"lib:test": "ng test openvidu-angular --no-watch --code-coverage",
"lib:e2e": "tsc --project ./e2e && npx mocha --recursive --timeout 30000 ./e2e/dist/angular.test.js",
"lib:e2e-ci": "cross-env LAUNCH_MODE=CI npm run lib:e2e",
"lib:doc-build": "npx compodoc -p src/doc/tsconfig.doc.json -c src/doc/.compodocrc.json",
"lib:doc-serve": "npx compodoc -p src/doc/tsconfig.doc.json --watch --serve -c src/doc/.compodocrc.json",
"webcomponent:build": "./node_modules/@angular/cli/bin/ng.js build openvidu-webcomponent --configuration production && node ./openvidu-webcomponent-build.js",
"webcomponent:serve-testapp": "npx http-server ./e2e/webcomponent-app/",
"webcomponent:e2e": "tsc --project ./e2e && npx mocha --recursive --timeout 30000 ./e2e/dist/webcomponent.test.js",
@ -43,6 +45,7 @@
"@angular/compiler": "13.0.0",
"@angular/compiler-cli": "13.0.0",
"@angular/elements": "13.0.0",
"@compodoc/compodoc": "^1.1.19",
"@types/chai": "4.3.0",
"@types/mocha": "9.1.0",
"@types/node": "16.11.6",

View File

@ -2,6 +2,10 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
/**
* @internal
*/
@Component({
selector: 'ov-audio-wave',
templateUrl: './audio-wave.component.html',
@ -9,7 +13,7 @@ import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
})
export class AudioWaveComponent implements OnInit, OnDestroy {
isSpeaking: boolean = false;
audioVolume: number = 0;
// audioVolume: number = 0;
private _streamManager: StreamManager;
@ -17,7 +21,7 @@ export class AudioWaveComponent implements OnInit, OnDestroy {
set streamManager(streamManager: StreamManager) {
this._streamManager = streamManager;
if(this._streamManager) {
if (this._streamManager) {
this._streamManager.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => {
this.isSpeaking = true;
});
@ -34,12 +38,11 @@ export class AudioWaveComponent implements OnInit, OnDestroy {
// console.log('AUDIO VOLUME', this.audioVolume);
// });
}
}
constructor() {}
ngOnDestroy(): void {
if(this._streamManager){
if (this._streamManager) {
this._streamManager.off('publisherStartSpeaking');
this._streamManager.off('publisherStopSpeaking');
}

View File

@ -1,5 +1,9 @@
import { Component, Input } from '@angular/core';
/**
* @internal
*/
@Component({
selector: 'ov-avatar-profile',
template: `

View File

@ -13,8 +13,40 @@ import { ParticipantService } from '../../services/participant/participant.servi
import { ParticipantAbstractModel } from '../../models/participant.model';
import { LayoutService } from '../../services/layout/layout.service';
import { StreamDirective } from '../../directives/template/openvidu-angular.directive';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
/**
*
* The **LayoutComponent** is hosted inside of the {@link VideoconferenceComponent}.
* It is in charge of displaying the participants streams layout.
*
* <div class="custom-table-container">
*
* <div>
* <h3>OpenVidu Angular Directives</h3>
*
* The LayoutComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovLayout** | {@link LayoutDirective} |
*
* </br>
*
* It is also providing us a way to **replace the {@link StreamComponent Stream Component}** (<span class="italic">which is hosted inside of it</span>) with a custom one.
* It will recognise the following directive in a child element.
*
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovStream** | {@link StreamDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-layout',
templateUrl: './layout.component.html',
@ -22,8 +54,14 @@ import { OpenViduAngularConfigService } from '../../services/config/openvidu-ang
changeDetection: ChangeDetectionStrategy.OnPush
})
export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
/**
* @ignore
*/
@ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>;
/**
* @ignore
*/
@ContentChild(StreamDirective)
set externalStream(externalStream: StreamDirective) {
// This directive will has value only when STREAM component tagget with '*ovStream' directive
@ -38,12 +76,10 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
protected localParticipantSubs: Subscription;
protected remoteParticipantsSubs: Subscription;
constructor(
protected layoutService: LayoutService,
protected participantService: ParticipantService,
private libService: OpenViduAngularConfigService,
private cd: ChangeDetectorRef
) {}
/**
* @ignore
*/
constructor(protected layoutService: LayoutService, protected participantService: ParticipantService, private cd: ChangeDetectorRef) {}
ngOnInit(): void {
this.subscribeToParticipants();
@ -51,10 +87,6 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
ngAfterViewInit() {
let timeout: number = 0;
// if (this.libService.isWebcomponent()) {
// timeout = 0;
// }
this.layoutService.initialize(timeout);
this.layoutService.update(timeout);
}
@ -67,7 +99,7 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
this.layoutService.clear();
}
protected subscribeToParticipants() {
private subscribeToParticipants() {
this.localParticipantSubs = this.participantService.localParticipantObs.subscribe((p) => {
this.localParticipant = p;
this.layoutService.update();

View File

@ -1,11 +1,17 @@
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
/**
* @internal
*/
export interface DialogData {
title: string;
description: string;
showActionButtons: boolean;
}
/**
* @internal
*/
@Component({
selector: 'ov-dialog-template',

View File

@ -1,10 +1,43 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
HostListener,
OnInit,
ViewChild
} from '@angular/core';
import { Subscription } from 'rxjs';
import { ChatMessage } from '../../../models/chat.model';
import { MenuType } from '../../../models/menu.model';
import { ChatService } from '../../../services/chat/chat.service';
import { SidenavMenuService } from '../../../services/sidenav-menu/sidenav-menu.service';
/**
*
* The **ChatPanelComponent** is hosted inside of the {@link PanelComponent}.
* It is in charge of displaying the session chat.
*
* <div class="custom-table-container">
* <div>
*
* <h3>OpenVidu Angular Directives</h3>
*
* The ChatPanelComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovChatPanel** | {@link ChatPanelDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-chat-panel',
templateUrl: './chat-panel.component.html',
@ -12,16 +45,31 @@ import { SidenavMenuService } from '../../../services/sidenav-menu/sidenav-menu.
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChatPanelComponent implements OnInit, AfterViewInit {
/**
* @ignore
*/
@ViewChild('chatScroll') chatScroll: ElementRef;
/**
* @ignore
*/
@ViewChild('chatInput') chatInput: ElementRef;
/**
* @ignore
*/
message: string;
messageList: ChatMessage[] = [];
isMenuOpened: boolean;
private chatMessageSubscription: Subscription;
/**
* @ignore
*/
constructor(private chatService: ChatService, private menuService: SidenavMenuService, private cd: ChangeDetectorRef) {}
/**
* @ignore
*/
@HostListener('document:keydown.escape', ['$event'])
onKeydownHandler(event: KeyboardEvent) {
if (this.menuService.isMenuOpened()) {
@ -44,6 +92,9 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
if (this.chatMessageSubscription) this.chatMessageSubscription.unsubscribe();
}
/**
* @ignore
*/
eventKeyPress(event) {
// Pressed 'Enter' key
if (event && event.keyCode === 13) {
@ -53,7 +104,7 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
}
sendMessage(): void {
if(!!this.message) {
if (!!this.message) {
this.chatService.sendMessage(this.message);
this.message = '';
}

View File

@ -4,6 +4,42 @@ import { ChatPanelDirective, ParticipantsPanelDirective } from '../../directives
import { MenuType } from '../../models/menu.model';
import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.service';
/**
*
* The **PanelComponent** is hosted inside of the {@link VideoconferenceComponent}.
* It is in charge of displaying the videoconference panels providing functionalities to the videoconference app
* such as the chat ({@link ChatPanelComponent}) and list of participants ({@link ParticipantsPanelComponent}) .
*
* <div class="custom-table-container">
* <div>
*
* <h3>OpenVidu Angular Directives</h3>
*
* The PanelComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovPanel** | {@link PanelDirective} |
*
* </br>
*
* It is also providing us a way to **replace the children panels** to the default panel.
* It will recognise the following directive in a child element.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovChatPanel** | {@link ChatPanelDirective} |
* | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-panel',
templateUrl: './panel.component.html',
@ -11,7 +47,14 @@ import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.ser
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PanelComponent implements OnInit {
/**
* @ignore
*/
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>;
/**
* @ignore
*/
@ContentChild('chatPanel', { read: TemplateRef }) chatPanelTemplate: TemplateRef<any>;
@ContentChild(ParticipantsPanelDirective)
@ -34,23 +77,28 @@ export class PanelComponent implements OnInit {
isParticipantsPanelOpened: boolean;
isChatPanelOpened: boolean;
menuSubscription: Subscription;
private menuSubscription: Subscription;
/**
* @ignore
*/
constructor(protected menuService: SidenavMenuService, private cd: ChangeDetectorRef) {}
ngOnInit(): void {
this.subscribeToPanelToggling();
}
subscribeToPanelToggling() {
this.menuSubscription = this.menuService.menuOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: MenuType }) => {
this.isChatPanelOpened = ev.opened && ev.type === MenuType.CHAT;
this.isParticipantsPanelOpened = ev.opened && ev.type === MenuType.PARTICIPANTS;
this.cd.markForCheck();
});
}
ngOnDestroy() {
this.isChatPanelOpened = false;
this.isParticipantsPanelOpened = false;
if (this.menuSubscription) this.menuSubscription.unsubscribe();
}
private subscribeToPanelToggling() {
this.menuSubscription = this.menuService.menuOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: MenuType }) => {
this.isChatPanelOpened = ev.opened && ev.type === MenuType.CHAT;
this.isParticipantsPanelOpened = ev.opened && ev.type === MenuType.PARTICIPANTS;
this.cd.markForCheck();
});
}
}

View File

@ -4,6 +4,54 @@ import { ParticipantPanelItemElementsDirective } from '../../../../directives/te
import { ParticipantAbstractModel } from '../../../../models/participant.model';
import { OpenViduAngularConfigService } from '../../../../services/config/openvidu-angular.config.service';
/**
*
* The **ParticipantPanelItemComponent** is hosted inside of the {@link ParticipantsPanelComponent}.
* It is in charge of displaying the participants information inside of the ParticipansPanelComponent.
*
* <div class="custom-table-container">
* <div>
* <h3>API Directives</h3>
*
* This component allows us to show or hide certain HTML elements with the following {@link https://angular.io/guide/attribute-directives Angular attribute directives}
* with the aim of fully customizing the ToolbarComponent.
*
* | **Name** | **Type** | **Reference** |
* | :----------------------------: | :-------: | :---------------------------------------------: |
* | **muteButton** | `boolean` | {@link ParticipantPanelItemMuteButtonDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link ApiDirectiveModule API Directives}</span>
* </p>
*
* </div>
* <div>
*
* <h3>OpenVidu Angular Directives</h3>
*
* The ParticipantPanelItemComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovParticipantPanelItem** | {@link ParticipantPanelItemDirective} |
*
* </br>
*
* It is also providing us a way to **add additional buttons** to the default participant panel item.
* It will recognise the following directive in a child element.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovParticipantPanelItemElements** | {@link ParticipantPanelItemElementsDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-participant-panel-item',
templateUrl: './participant-panel-item.component.html',
@ -11,10 +59,20 @@ import { OpenViduAngularConfigService } from '../../../../services/config/openvi
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
/**
* @ignore
*/
@ContentChild('participantPanelItemElements', { read: TemplateRef }) participantPanelItemElementsTemplate: TemplateRef<any>;
/**
* @ignore
*/
showMuteButton: boolean = true;
private muteButtonSub: Subscription;
/**
* @ignore
*/
@ContentChild(ParticipantPanelItemElementsDirective)
set externalItemElements(externalItemElements: ParticipantPanelItemElementsDirective) {
// This directive will has value only when ITEM ELEMENTS component tagget with '*ovParticipantPanelItemElements' directive
@ -25,11 +83,18 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
}
@Input()
set participant(p: ParticipantAbstractModel) {
this._participant = p;
set participant(participant: ParticipantAbstractModel) {
this._participant = participant;
}
/**
* @ignore
*/
_participant: ParticipantAbstractModel;
/**
* @ignore
*/
constructor(private libService: OpenViduAngularConfigService, private cd: ChangeDetectorRef) {}
ngOnInit(): void {
@ -39,6 +104,9 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
if (this.muteButtonSub) this.muteButtonSub.unsubscribe();
}
/**
* @ignore
*/
toggleMuteForcibly() {
this._participant.setMutedForcibly(!this._participant.isMutedForcibly);
}

View File

@ -5,6 +5,39 @@ import { SidenavMenuService } from '../../../..//services/sidenav-menu/sidenav-m
import { ParticipantPanelItemDirective } from '../../../../directives/template/openvidu-angular.directive';
import { Subscription } from 'rxjs';
/**
*
* The **ParticipantsPanelComponent** is hosted inside of the {@link PanelComponent}.
* It is in charge of displaying the participants connected to the session.
* This component is composed by the {@link ParticipantPanelItemComponent}.
*
* <div class="custom-table-container">
* <div>
*
* <h3>OpenVidu Angular Directives</h3>
*
* The ParticipantsPanelComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} |
*
* </br>
*
* As the ParticipantsPanelComponent is composed by ParticipantPanelItemComponent, it is also providing us a way to **replace the participant item** with a custom one.
* It will recognise the following directive in a child element.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovParticipantPanelItem** | {@link ParticipantPanelItemDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-participants-panel',
templateUrl: './participants-panel.component.html',
@ -15,8 +48,9 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy {
localParticipant: any;
remoteParticipants: ParticipantAbstractModel[] = [];
private localParticipantSubs: Subscription;
private remoteParticipantsSubs: Subscription;
/**
* @ignore
*/
@ContentChild('participantPanelItem', { read: TemplateRef }) participantPanelItemTemplate: TemplateRef<any>;
@ContentChild(ParticipantPanelItemDirective)
@ -28,16 +62,19 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy {
}
}
private localParticipantSubs: Subscription;
private remoteParticipantsSubs: Subscription;
/**
* @ignore
*/
constructor(
protected participantService: ParticipantService,
protected menuService: SidenavMenuService,
private cd: ChangeDetectorRef
) {
}
) {}
ngOnInit(): void {
this.localParticipantSubs = this.participantService.localParticipantObs.subscribe((p: ParticipantAbstractModel) => {
this.localParticipant = p;
// Mark for re-rendering using an impure pipe 'streamsTypesEnabled'

View File

@ -13,6 +13,9 @@ import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { ParticipantService } from '../../services/participant/participant.service';
import { StorageService } from '../../services/storage/storage.service';
/**
* @internal
*/
@Component({
selector: 'ov-pre-join',
templateUrl: './pre-join.component.html',

View File

@ -27,6 +27,11 @@ import { LayoutService } from '../../services/layout/layout.service';
import { Subscription, skip } from 'rxjs';
import { MenuType } from '../../models/menu.model';
import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.service';
import { PlatformService } from '../../services/platform/platform.service';
/**
* @internal
*/
@Component({
selector: 'ov-session',
@ -68,7 +73,8 @@ export class SessionComponent implements OnInit {
protected chatService: ChatService,
protected tokenService: TokenService,
protected layoutService: LayoutService,
protected menuService: SidenavMenuService
protected menuService: SidenavMenuService,
private platformService: PlatformService
) {
this.log = this.loggerSrv.get('SessionComponent');
}
@ -107,9 +113,9 @@ export class SessionComponent implements OnInit {
await this.connectToSession();
// Workaround, firefox does not have audio when publisher join with muted camera
// if (this.platformService.isFirefox() && !this.localUserService.hasCameraVideoActive()) {
// this.openviduService.publishVideo(this.localUserService.getMyCameraPublisher(), true);
// this.openviduService.publishVideo(this.localUserService.getMyCameraPublisher(), false);
// if (this.platformService.isFirefox() && !this.participantService.hasCameraVideoActive()) {
// this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), true);
// this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), false);
// }
}

View File

@ -55,7 +55,7 @@
<span *ngIf="videoSizeIcon === videoSizeIconEnum.NORMAL">Zoom out</span>
<span *ngIf="videoSizeIcon === videoSizeIconEnum.BIG">Zoom in</span>
</button>
<button mat-menu-item id="volumeButton" *ngIf="!this._stream.local" (click)="toggleSound()">
<button mat-menu-item id="volumeButton" *ngIf="!this._stream.local" (click)="toggleMuteForcibly()">
<mat-icon *ngIf="!_stream.participant.isMutedForcibly">volume_up</mat-icon>
<span *ngIf="!_stream.participant.isMutedForcibly">Mute sound</span>

View File

@ -14,44 +14,105 @@ import { StreamModel } from '../../models/participant.model';
import { ParticipantService } from '../../services/participant/participant.service';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
/**
* The **StreamComponent** is hosted inside of the {@link LayoutComponent}.
* It is in charge of displaying the participant video stream in the videoconference layout.
*
* <div class="custom-table-container">
* <div>
* <h3>API Directives</h3>
*
* This component allows us to show or hide certain HTML elements with the following {@link https://angular.io/guide/attribute-directives Angular attribute directives}
* with the aim of fully customizing the StreamComponent.
*
* | **Parameter** | **Type** | **Reference** |
* | :----------------------------: | :-------: | :---------------------------------------------: |
* | **displayParticipantName** | `boolean` | {@link StreamDisplayParticipantNameDirective} |
* | **displayAudioDetection** | `boolean` | {@link StreamDisplayAudioDetectionDirective} |
* | **settingsButton** | `boolean` | {@link StreamSettingsButtonDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link ApiDirectiveModule API Directives}</span>
* </p>
* </div>
*
* <div>
* <h3>OpenVidu Angular Directives</h3>
*
* The StreamComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovStream** | {@link StreamDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
*
* </div>
*/
@Component({
selector: 'ov-stream',
templateUrl: './stream.component.html',
styleUrls: ['./stream.component.css']
})
export class StreamComponent implements OnInit {
/**
* @ignore
*/
@ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger;
/**
* @ignore
*/
@ViewChild('menu') menu: MatMenuPanel;
/**
* @ignore
*/
videoSizeIconEnum = VideoSizeIcon;
/**
* @ignore
*/
videoTypeEnum = VideoType;
/**
* @ignore
*/
videoSizeIcon: VideoSizeIcon = VideoSizeIcon.BIG;
/**
* @ignore
*/
toggleNickname: boolean;
/**
* @ignore
*/
_stream: StreamModel;
/**
* @ignore
*/
nickname: string;
/**
* @ignore
*/
isMinimal: boolean = false;
/**
* @ignore
*/
showNickname: boolean = true;
/**
* @ignore
*/
showAudioDetection: boolean = true;
/**
* @ignore
*/
showSettingsButton: boolean = true;
private _streamContainer: ElementRef;
private minimalSub: Subscription;
private displayParticipantNameSub: Subscription;
private displayAudioDetectionSub: Subscription;
private settingsButtonSub: Subscription;
constructor(
protected documentService: DocumentService,
protected openviduService: OpenViduService,
protected layoutService: LayoutService,
protected participantService: ParticipantService,
protected storageService: StorageService,
protected cdkSrv: CdkOverlayService,
private libService: OpenViduAngularConfigService
) {}
/**
* @ignore
*/
@ViewChild('streamContainer', { static: false, read: ElementRef })
set streamContainer(streamContainer: ElementRef) {
setTimeout(() => {
@ -73,6 +134,9 @@ export class StreamComponent implements OnInit {
}
}
/**
* @ignore
*/
@ViewChild('nicknameInput')
set nicknameInputElement(element: ElementRef) {
setTimeout(() => {
@ -80,6 +144,25 @@ export class StreamComponent implements OnInit {
});
}
private _streamContainer: ElementRef;
private minimalSub: Subscription;
private displayParticipantNameSub: Subscription;
private displayAudioDetectionSub: Subscription;
private settingsButtonSub: Subscription;
/**
* @ignore
*/
constructor(
protected documentService: DocumentService,
protected openviduService: OpenViduService,
protected layoutService: LayoutService,
protected participantService: ParticipantService,
protected storageService: StorageService,
protected cdkSrv: CdkOverlayService,
private libService: OpenViduAngularConfigService
) {}
ngOnInit() {
this.subscribeToStreamDirectives();
}
@ -89,8 +172,12 @@ export class StreamComponent implements OnInit {
if (this.settingsButtonSub) this.settingsButtonSub.unsubscribe();
if (this.displayAudioDetectionSub) this.displayAudioDetectionSub.unsubscribe();
if (this.displayParticipantNameSub) this.displayParticipantNameSub.unsubscribe();
if (this.minimalSub) this.minimalSub.unsubscribe();
}
/**
* @ignore
*/
toggleVideoEnlarged() {
if (!!this._stream.streamManager?.stream?.connection?.connectionId) {
if (this.openviduService.isMyOwnConnection(this._stream.streamManager?.stream?.connection?.connectionId)) {
@ -102,6 +189,9 @@ export class StreamComponent implements OnInit {
this.layoutService.update();
}
/**
* @ignore
*/
toggleVideoMenu(event) {
if (this.menuTrigger.menuOpen) {
this.menuTrigger.closeMenu();
@ -111,16 +201,25 @@ export class StreamComponent implements OnInit {
this.menuTrigger.openMenu();
}
toggleSound() {
/**
* @ignore
*/
toggleMuteForcibly() {
this._stream.participant.setMutedForcibly(!this._stream.participant.isMutedForcibly);
}
/**
* @ignore
*/
toggleNicknameForm() {
if (this._stream.participant.local) {
this.toggleNickname = !this.toggleNickname;
}
}
/**
* @ignore
*/
updateNickname(event) {
if (event?.keyCode === 13 || event?.type === 'focusout') {
if (!!this.nickname) {
@ -132,6 +231,9 @@ export class StreamComponent implements OnInit {
}
}
/**
* @ignore
*/
async replaceScreenTrack() {
const properties: PublisherProperties = {
videoSource: ScreenType.SCREEN,
@ -147,7 +249,6 @@ export class StreamComponent implements OnInit {
}
private subscribeToStreamDirectives() {
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
this.isMinimal = value;
});

View File

@ -29,6 +29,60 @@ import { MenuType } from '../../models/menu.model';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
import { ToolbarAdditionalButtonsDirective } from '../../directives/template/openvidu-angular.directive';
/**
*
* The **ToolbarComponent** is hosted inside of the {@link VideoconferenceComponent}.
* It is in charge of displaying the participants controlls for handling the media, panels and more videoconference features.
*
* <div class="custom-table-container">
* <div>
* <h3>API Directives</h3>
*
* This component allows us to show or hide certain HTML elements with the following {@link https://angular.io/guide/attribute-directives Angular attribute directives}
* with the aim of fully customizing the ToolbarComponent.
*
* | **Name** | **Type** | **Reference** |
* | :----------------------------: | :-------: | :---------------------------------------------: |
* | **screenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
* | **fullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
* | **leaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
* | **chatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
* | **participantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
* | **displayLogo** | `boolean` | {@link ToolbarDisplayLogoDirective} |
* | **displaySessionName** | `boolean` | {@link ToolbarDisplaySessionNameDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link ApiDirectiveModule API Directives}</span>
* </p>
*
* </div>
* <div>
*
* <h3>OpenVidu Angular Directives</h3>
*
* The ToolbarComponent can be replaced with a custom component. It provides us the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* for doing this.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovToolbar** | {@link ToolbarDirective} |
*
* </br>
*
* It is also providing us a way to **add additional buttons** to the default toolbar.
* It will recognise the following directive in a child element.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovToolbarAdditionalButtons** | {@link ToolbarAdditionalButtonsDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-toolbar',
templateUrl: './toolbar.component.html',
@ -36,8 +90,14 @@ import { ToolbarAdditionalButtonsDirective } from '../../directives/template/ope
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ToolbarComponent implements OnInit, OnDestroy {
/**
* @ignore
*/
@ContentChild('toolbarAdditionalButtons', { read: TemplateRef }) toolbarAdditionalButtonsTemplate: TemplateRef<any>;
/**
* @ignore
*/
@ContentChild(ToolbarAdditionalButtonsDirective)
set externalAdditionalButtons(externalAdditionalButtons: ToolbarAdditionalButtonsDirective) {
// This directive will has value only when ADDITIONAL BUTTONS component tagget with '*ovToolbarAdditionalButtons' directive
@ -55,26 +115,86 @@ export class ToolbarComponent implements OnInit, OnDestroy {
@Output() onParticipantsPanelButtonClicked = new EventEmitter<any>();
@Output() onChatPanelButtonClicked = new EventEmitter<any>();
/**
* @ignore
*/
session: Session;
/**
* @ignore
*/
unreadMessages: number = 0;
/**
* @ignore
*/
messageList: ChatMessage[] = [];
/**
* @ignore
*/
isScreenShareActive: boolean;
/**
* @ignore
*/
isWebcamVideoActive: boolean;
/**
* @ignore
*/
isWebcamAudioActive: boolean;
/**
* @ignore
*/
isConnectionLost: boolean;
/**
* @ignore
*/
hasVideoDevices: boolean;
/**
* @ignore
*/
hasAudioDevices: boolean;
/**
* @ignore
*/
isFullscreenActive: boolean = false;
/**
* @ignore
*/
isChatOpened: boolean = false;
/**
* @ignore
*/
isParticipantsOpened: boolean = false;
/**
* @ignore
*/
isMinimal: boolean = false;
/**
* @ignore
*/
showScreenshareButton = true;
/**
* @ignore
*/
showFullscreenButton: boolean = true;
/**
* @ignore
*/
showLeaveButton: boolean = true;
/**
* @ignore
*/
showParticipantsPanelButton: boolean = true;
/**
* @ignore
*/
showChatPanelButton: boolean = true;
/**
* @ignore
*/
showLogo: boolean = true;
/**
* @ignore
*/
showSessionName: boolean = true;
private log: ILogger;
@ -91,25 +211,9 @@ export class ToolbarComponent implements OnInit, OnDestroy {
private displaySessionNameSub: Subscription;
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;
}
}
/**
* @ignore
*/
constructor(
protected documentService: DocumentService,
protected chatService: ChatService,
@ -125,6 +229,30 @@ export class ToolbarComponent implements OnInit, OnDestroy {
) {
this.log = this.loggerSrv.get('ToolbarComponent');
}
/**
* @ignore
*/
@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;
}
}
/**
* @ignore
*/
@HostListener('document:keydown', ['$event'])
keyDown(event: KeyboardEvent) {
if (event.key === 'F11') {
event.preventDefault();
this.toggleFullscreen();
this.currentWindowHeight = window.innerHeight;
return false;
}
}
async ngOnInit() {
this.subscribeToToolbarDirectives();
@ -151,8 +279,12 @@ export class ToolbarComponent implements OnInit, OnDestroy {
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
if (this.displaySessionNameSub) this.displaySessionNameSub.unsubscribe();
if (this.minimalSub) this.minimalSub.unsubscribe();
}
/**
* @ignore
*/
toggleMicrophone() {
this.onMicrophoneButtonClicked.emit();
@ -166,6 +298,9 @@ export class ToolbarComponent implements OnInit, OnDestroy {
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), !this.participantService.hasScreenAudioActive());
}
/**
* @ignore
*/
async toggleCamera() {
this.onCameraButtonClicked.emit();
@ -200,6 +335,9 @@ export class ToolbarComponent implements OnInit, OnDestroy {
}
}
/**
* @ignore
*/
async toggleScreenShare() {
this.onScreenshareButtonClicked.emit();
@ -277,22 +415,34 @@ export class ToolbarComponent implements OnInit, OnDestroy {
}
}
/**
* @ignore
*/
leaveSession() {
this.log.d('Leaving session...');
this.openviduService.disconnect();
this.onLeaveButtonClicked.emit();
}
/**
* @ignore
*/
toggleParticipantsPanel() {
this.onParticipantsPanelButtonClicked.emit();
this.menuService.toggleMenu(MenuType.PARTICIPANTS);
}
/**
* @ignore
*/
toggleChatPanel() {
this.onChatPanelButtonClicked.emit();
this.menuService.toggleMenu(MenuType.CHAT);
}
/**
* @ignore
*/
toggleFullscreen() {
this.isFullscreenActive = !this.isFullscreenActive;
this.documentService.toggleFullscreen('session-container');

View File

@ -19,6 +19,9 @@ import { ActionService } from '../../services/action/action.service';
import { ParticipantService } from '../../services/participant/participant.service';
import { ParticipantAbstractModel } from '../../models/participant.model';
/**
* @internal
*/
@Component({
selector: 'ov-user-settings',
templateUrl: './user-settings.component.html',

View File

@ -2,6 +2,9 @@ import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular
import { StreamManager } from 'openvidu-browser';
import { VideoType } from '../../models/video-type.model';
/**
* @internal
*/
@Component({
selector: 'ov-video',
template: `

View File

@ -48,12 +48,10 @@
(onParticipantsPanelButtonClicked)="onParticipantsPanelButtonClicked()"
(onChatPanelButtonClicked)="onChatPanelButtonClicked()"
>
<ng-template #toolbarAdditionalButtons>
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container>
</ng-template>
</ov-toolbar>
<ng-template #toolbarAdditionalButtons>
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container>
</ng-template>
</ov-toolbar>
</ng-template>
<ng-template #defaultPanel>
@ -84,11 +82,11 @@
<ng-template #defaultParticipantPanelItem let-participant>
<ov-participant-panel-item [participant]="participant" id="default-participant-panel-item">
<ng-template #participantPanelItemElements>
<ng-container *ngTemplateOutlet="openviduAngularParticipantPanelItemElementsTemplate; context: { $implicit: participant }"></ng-container>
<ng-container
*ngTemplateOutlet="openviduAngularParticipantPanelItemElementsTemplate; context: { $implicit: participant }"
></ng-container>
</ng-template>
</ov-participant-panel-item>
</ng-template>

View File

@ -25,6 +25,7 @@ import {
} from '../../directives/template/openvidu-angular.directive';
import { ILogger } from '../../models/logger.model';
import { ParticipantProperties } from '../../models/participant.model';
import { TokenModel } from '../../models/token.model';
import { ActionService } from '../../services/action/action.service';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
import { DeviceService } from '../../services/device/device.service';
@ -34,6 +35,68 @@ import { ParticipantService } from '../../services/participant/participant.servi
import { StorageService } from '../../services/storage/storage.service';
import { TokenService } from '../../services/token/token.service';
/**
* The **VideoconferenceComponent** is the parent of all OpenVidu components.
* It allow us to create a modern, useful and powerful videoconference apps with ease.
*
* <div class="custom-table-container">
* <div>
* <h3>API Directives</h3>
*
* This component allows us to show or hide certain HTML elements with the following {@link https://angular.io/guide/attribute-directives Angular attribute directives}
* with the aim of fully customizing the videoconference application.
*
* | **Parameter** | **Type** | **Reference** |
* | :----------------------------: | :-------: | :---------------------------------------------: |
* | **minimal** | `boolean` | {@link MinimalDirective} |
* | **prejoin** | `boolean` | {@link PrejoinDirective} |
* | **participantName** | `string` | {@link ParticipantNameDirective} |
* | **videoMuted** | `boolean` | {@link VideoMutedDirective} |
* | **audioMuted** | `boolean` | {@link AudioMutedDirective} |
* | **toolbarScreenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
* | **toolbarFullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
* | **toolbarLeaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
* | **toolbarChatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
* | **toolbarParticipantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
* | **toolbarDisplayLogo** | `boolean` | {@link ToolbarDisplayLogoDirective} |
* | **toolbarDisplaySessionName** | `boolean` | {@link ToolbarDisplaySessionNameDirective} |
* | **streamDisplayParticipantName** | `boolean` | {@link StreamDisplayParticipantNameDirective} |
* | **streamDisplayAudioDetection** | `boolean` | {@link StreamDisplayAudioDetectionDirective} |
* | **streamSettingsButton** | `boolean` | {@link StreamSettingsButtonDirective} |
* | **participantPanelItemMuteButton** | `boolean` | {@link ParticipantPanelItemMuteButtonDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link ApiDirectiveModule API Directives}</span>
* </p>
* </div>
*
* <div>
*
* <h3>OpenVidu Angular Directives</h3>
*
*
* The VideoconferenceComponent is also providing us a way to **replace the default templates** with a custom one.
* It will recognise the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* in the elements added as children.
*
* | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:|
* | ***ovToolbar** | {@link ToolbarDirective} |
* | ***ovToolbarAdditionalButtons** | {@link ToolbarAdditionalButtonsDirective} |
* | ***ovPanel** | {@link PanelDirective} |
* | ***ovChatPanel** | {@link ChatPanelDirective} |
* | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} |
* | ***ovParticipantPanelItem** | {@link ParticipantPanelItemDirective} |
* | ***ovParticipantPanelItemElements** | {@link ParticipantPanelItemElementsDirective} |
* | ***ovLayout** | {@link LayoutDirective} |
* | ***ovStream** | {@link StreamDirective} |
*
* <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
* </p>
* </div>
* </div>
*/
@Component({
selector: 'ov-videoconference',
templateUrl: './videoconference.component.html',
@ -41,40 +104,124 @@ import { TokenService } from '../../services/token/token.service';
})
export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewInit {
// *** Toolbar ***
/**
* @internal
*/
@ContentChild(ToolbarDirective) externalToolbar: ToolbarDirective;
/**
* @internal
*/
@ContentChild(ToolbarAdditionalButtonsDirective) externalToolbarAdditionalButtons: ToolbarAdditionalButtonsDirective;
// *** Panels ***
/**
* @internal
*/
@ContentChild(PanelDirective) externalPanel: PanelDirective;
/**
* @internal
*/
@ContentChild(ChatPanelDirective) externalChatPanel: ChatPanelDirective;
/**
* @internal
*/
@ContentChild(ParticipantsPanelDirective) externalParticipantsPanel: ParticipantsPanelDirective;
/**
* @internal
*/
@ContentChild(ParticipantPanelItemDirective) externalParticipantPanelItem: ParticipantPanelItemDirective;
/**
* @internal
*/
@ContentChild(ParticipantPanelItemElementsDirective) externalParticipantPanelItemElements: ParticipantPanelItemElementsDirective;
// *** Layout ***
/**
* @internal
*/
@ContentChild(LayoutDirective) externalLayout: LayoutDirective;
/**
* @internal
*/
@ContentChild(StreamDirective) externalStream: StreamDirective;
/**
* @internal
*/
@ViewChild('defaultToolbar', { static: false, read: TemplateRef }) defaultToolbarTemplate: TemplateRef<any>;
/**
* @internal
*/
@ViewChild('defaultPanel', { static: false, read: TemplateRef }) defaultPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
@ViewChild('defaultChatPanel', { static: false, read: TemplateRef }) defaultChatPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
@ViewChild('defaultParticipantsPanel', { static: false, read: TemplateRef }) defaultParticipantsPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
@ViewChild('defaultParticipantPanelItem', { static: false, read: TemplateRef }) defaultParticipantPanelItemTemplate: TemplateRef<any>;
/**
* @internal
*/
@ViewChild('defaultLayout', { static: false, read: TemplateRef }) defaultLayoutTemplate: TemplateRef<any>;
/**
* @internal
*/
@ViewChild('defaultStream', { static: false, read: TemplateRef }) defaultStreamTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularToolbarTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularChatPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularParticipantsPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularParticipantPanelItemTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularParticipantPanelItemElementsTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularLayoutTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularStreamTemplate: TemplateRef<any>;
// *** Parameters ***
// @Input() sessionName: string;
// @Input() participantName: string;
/**
* @param {TokenModel} tokens The tokens parameter must be an object with `webcam` and `screen` fields.
* Both of them are `string` type. See {@link TokenModel}
*/
@Input()
set tokens(tokens: { webcam: string; screen: string }) {
set tokens(tokens: TokenModel) {
if (!tokens || (!tokens.webcam && !tokens.screen)) {
//No tokens received
// throw new Error('No tokens received');
@ -109,18 +256,38 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
// Event sent when participant has been created
@Output() onParticipantCreated = new EventEmitter<any>();
/**
* @internal
*/
joinSessionClicked: boolean = false;
/**
* @internal
*/
participantReady: boolean = false;
/**
* @internal
*/
canPublish: boolean = false;
/**
* @internal
*/
error: boolean = false;
/**
* @internal
*/
errorMessage: string = '';
/**
* @internal
*/
showPrejoin: boolean = true;
private externalParticipantName: string;
private prejoinSub: Subscription;
private participantNameSub: Subscription;
private log: ILogger;
/**
* @internal
*/
constructor(
private loggerSrv: LoggerService,
private storageSrv: StorageService,
@ -174,6 +341,9 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
if (this.participantNameSub) this.participantNameSub.unsubscribe();
}
/**
* @internal
*/
ngAfterViewInit() {
if (this.externalToolbar) {
this.openviduAngularToolbarTemplate = this.externalToolbar.template;
@ -239,34 +409,60 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
}
}
/**
* @internal
*/
_onJoinButtonClicked() {
this.joinSessionClicked = true;
this.onJoinButtonClicked.emit();
}
/**
* @internal
*/
onLeaveButtonClicked() {
this.joinSessionClicked = false;
this.participantReady = false;
this.onToolbarLeaveButtonClicked.emit();
}
/**
* @internal
*/
onCameraButtonClicked() {
this.onToolbarCameraButtonClicked.emit();
}
/**
* @internal
*/
onMicrophoneButtonClicked() {
this.onToolbarMicrophoneButtonClicked.emit();
}
/**
* @internal
*/
onScreenshareButtonClicked() {
this.onToolbarScreenshareButtonClicked.emit();
}
/**
* @internal
*/
onFullscreenButtonClicked() {
this.onToolbarFullscreenButtonClicked.emit();
}
/**
* @internal
*/
onParticipantsPanelButtonClicked() {
this.onToolbarParticipantsPanelButtonClicked.emit();
}
/**
* @internal
*/
onChatPanelButtonClicked() {
this.onToolbarChatPanelButtonClicked.emit();
}
/**
* @internal
*/
_onSessionCreated(event: Session) {
this.onSessionCreated.emit(event);
}

View File

@ -23,6 +23,7 @@ import {
ParticipantNameDirective
} from './videoconference.directive';
@NgModule({
declarations: [
MinimalDirective,

View File

@ -1,6 +1,21 @@
import { Directive, AfterViewInit, OnDestroy, Input, ElementRef } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
/**
* The **muteButton** directive allows show/hide the muted button in participant panel item component.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `participantPanelItem` component:
*
* @example
* <ov-videoconference [participantPanelItemMuteButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ParticipantPanelItemComponent}.
* @example
* <ov-participant-panel-item [muteButton]="false"></ov-participant-panel-item>
*/
@Directive({
selector: 'ov-videoconference[participantPanelItemMuteButton], ov-participant-panel-item[muteButton]'
})

View File

@ -1,6 +1,21 @@
import { AfterViewInit, Directive, ElementRef, Input, OnDestroy } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
/**
* The **displayParticipantName** directive allows show/hide the participants name in stream component.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `stream` component:
*
* @example
* <ov-videoconference [streamDisplayParticipantName]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link StreamComponent}.
* @example
* <ov-stream [displayParticipantName]="false"></ov-stream>
*/
@Directive({
selector: 'ov-videoconference[streamDisplayParticipantName], ov-stream[displayParticipantName]'
})
@ -37,6 +52,21 @@ export class StreamDisplayParticipantNameDirective implements AfterViewInit, OnD
}
}
/**
* The **displayAudioDetection** directive allows show/hide the participants audio detection in stream component.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `stream` component:
*
* @example
* <ov-videoconference [streamDisplayAudioDetection]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link StreamComponent}.
* @example
* <ov-stream [displayAudioDetection]="false"></ov-stream>
*/
@Directive({
selector: 'ov-videoconference[streamDisplayAudioDetection], ov-stream[displayAudioDetection]'
})
@ -71,6 +101,21 @@ export class StreamDisplayAudioDetectionDirective implements AfterViewInit, OnDe
}
}
/**
* The **settingsButton** directive allows show/hide the participants settings button in stream component.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `stream` component:
*
* @example
* <ov-videoconference [streamSettingsButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link StreamComponent}.
* @example
* <ov-stream [settingsButton]="false"></ov-stream>
*/
@Directive({
selector: 'ov-videoconference[streamSettingsButton], ov-stream[settingsButton]'
})

View File

@ -1,21 +1,46 @@
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
/**
* The **screenshareButton** directive allows show/hide the screenshare toolbar button.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarScreenshareButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [screenshareButton]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarScreenshareButton], ov-toolbar[screenshareButton]'
})
export class ToolbarScreenshareButtonDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarScreenshareButton(value: boolean) {
this.screenshareValue = value;
this.update(this.screenshareValue);
}
/**
* @ignore
*/
@Input() set screenshareButton(value: boolean) {
this.screenshareValue = value;
this.update(this.screenshareValue);
}
screenshareValue: boolean = true;
private screenshareValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -25,33 +50,58 @@ export class ToolbarScreenshareButtonDirective implements AfterViewInit, OnDestr
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.screenshareValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.screenshareButton.getValue() !== value) {
this.libService.screenshareButton.next(value);
}
}
}
/**
* The **fullscreenButton** directive allows show/hide the fullscreen toolbar button.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarFullscreenButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [fullscreenButton]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarFullscreenButton], ov-toolbar[fullscreenButton]'
})
export class ToolbarFullscreenButtonDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarFullscreenButton(value: boolean) {
this.fullscreenValue = value;
this.update(this.fullscreenValue);
}
/**
* @ignore
*/
@Input() set fullscreenButton(value: boolean) {
this.fullscreenValue = value;
this.update(this.fullscreenValue);
}
fullscreenValue: boolean = true;
private fullscreenValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -60,33 +110,57 @@ export class ToolbarFullscreenButtonDirective implements AfterViewInit, OnDestro
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.fullscreenValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.fullscreenButton.getValue() !== value) {
this.libService.fullscreenButton.next(value);
}
}
}
/**
* The **leaveButton** directive allows show/hide the leave toolbar button.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarLeaveButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [leaveButton]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarLeaveButton], ov-toolbar[leaveButton]'
})
export class ToolbarLeaveButtonDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarLeaveButton(value: boolean) {
this.leaveValue = value;
this.update(this.leaveValue);
}
/**
* @ignore
*/
@Input() set leaveButton(value: boolean) {
this.leaveValue = value;
this.update(this.leaveValue);
}
leaveValue: boolean = true;
private leaveValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -96,33 +170,58 @@ export class ToolbarLeaveButtonDirective implements AfterViewInit, OnDestroy {
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.leaveValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.leaveButton.getValue() !== value) {
this.libService.leaveButton.next(value);
}
}
}
/**
* The **participantsPanelButton** directive allows show/hide the participants panel toolbar button.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarParticipantsPanelButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [participantsPanelButton]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarParticipantsPanelButton], ov-toolbar[participantsPanelButton]'
})
export class ToolbarParticipantsPanelButtonDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarParticipantsPanelButton(value: boolean) {
this.participantsPanelValue = value;
this.update(this.participantsPanelValue);
}
/**
* @ignore
*/
@Input() set participantsPanelButton(value: boolean) {
this.participantsPanelValue = value;
this.update(this.participantsPanelValue);
}
participantsPanelValue: boolean = true;
private participantsPanelValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -132,32 +231,56 @@ export class ToolbarParticipantsPanelButtonDirective implements AfterViewInit, O
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.participantsPanelValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.participantsPanelButton.getValue() !== value) {
this.libService.participantsPanelButton.next(value);
}
}
}
/**
* The **chatPanelButton** directive allows show/hide the chat panel toolbar button.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarChatPanelButton]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [chatPanelButton]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarChatPanelButton], ov-toolbar[chatPanelButton]'
})
export class ToolbarChatPanelButtonDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarChatPanelButton(value: boolean) {
this.toolbarChatPanelValue = value;
this.update(this.toolbarChatPanelValue);
}
/**
* @ignore
*/
@Input() set chatPanelButton(value: boolean) {
this.toolbarChatPanelValue = value;
this.update(this.toolbarChatPanelValue);
}
toolbarChatPanelValue: boolean = true;
private toolbarChatPanelValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -167,33 +290,57 @@ export class ToolbarChatPanelButtonDirective implements AfterViewInit, OnDestroy
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.toolbarChatPanelValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.chatPanelButton.getValue() !== value) {
this.libService.chatPanelButton.next(value);
}
}
}
/**
* The **displaySessionName** directive allows show/hide the session name.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarDisplaySessionName]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [displaySessionName]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarDisplaySessionName], ov-toolbar[displaySessionName]'
})
export class ToolbarDisplaySessionNameDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarDisplaySessionName(value: boolean) {
this.displaySessionValue = value;
this.update(this.displaySessionValue);
}
/**
* @ignore
*/
@Input() set displaySessionName(value: boolean) {
this.displaySessionValue = value;
this.update(this.displaySessionValue);
}
displaySessionValue: boolean = true;
private displaySessionValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -203,33 +350,57 @@ export class ToolbarDisplaySessionNameDirective implements AfterViewInit, OnDest
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.displaySessionValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.displaySessionName.getValue() !== value) {
this.libService.displaySessionName.next(value);
}
}
}
/**
* The **displayLogo** directive allows show/hide the branding logo.
*
* Default: `true`
*
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
*
* @example
* <ov-videoconference [toolbarDisplayLogo]="false"></ov-videoconference>
*
* \
* And it also can be used in the {@link ToolbarComponent}.
* @example
* <ov-toolbar [displayLogo]="false"></ov-toolbar>
*/
@Directive({
selector: 'ov-videoconference[toolbarDisplayLogo], ov-toolbar[displayLogo]'
})
export class ToolbarDisplayLogoDirective implements AfterViewInit, OnDestroy {
/**
* @ignore
*/
@Input() set toolbarDisplayLogo(value: boolean) {
this.displayLogoValue = value;
this.update(this.displayLogoValue);
}
/**
* @ignore
*/
@Input() set displayLogo(value: boolean) {
this.displayLogoValue = value;
this.update(this.displayLogoValue);
}
displayLogoValue: boolean = true;
private displayLogoValue: boolean = true;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngAfterViewInit() {
@ -239,12 +410,12 @@ export class ToolbarDisplayLogoDirective implements AfterViewInit, OnDestroy {
ngOnDestroy(): void {
this.clear();
}
clear() {
private clear() {
this.displayLogoValue = true;
this.update(true);
}
update(value: boolean) {
private update(value: boolean) {
if (this.libService.displayLogo.getValue() !== value) {
this.libService.displayLogo.next(value);
}
@ -253,7 +424,10 @@ export class ToolbarDisplayLogoDirective implements AfterViewInit, OnDestroy {
// * Private directives *
// Load default OpenVidu logo if custom one is not exist
/**
* Load default OpenVidu logo if custom one is not exist
* @internal
*/
@Directive({
selector: 'img[ovLogo]'
})

View File

@ -1,21 +1,49 @@
import { Directive, Input, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
/**
* The **minimal** directive applies a minimal UI hiding all controls except for cam and mic.
*
* It is only available for {@link VideoconferenceComponent}.
*
* Default: `false`
*
* @example
* <ov-videoconference [minimal]="true"></ov-videoconference>
*/
@Directive({
selector: 'ov-videoconference[minimal]'
})
export class MinimalDirective implements OnDestroy {
/**
* @ignore
*/
@Input() set minimal(value: boolean) {
this.update(value);
}
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
/**
* @ignore
*/
ngOnDestroy(): void {
this.clear();
}
/**
* @ignore
*/
clear() {
this.update(false);
}
/**
* @ignore
*/
update(value: boolean) {
if (this.libService.minimal.getValue() !== value) {
this.libService.minimal.next(value);
@ -23,44 +51,102 @@ export class MinimalDirective implements OnDestroy {
}
}
/**
* The **participantName** directive sets the participant name. It can be useful for aplications which doesn't need the prejoin page or applications which uses the **openvidu-webcomponent**
*
* It is only available for {@link VideoconferenceComponent}.
*
* @example
* <ov-videoconference [participantName]="'OpenVidu'"></ov-videoconference>
*/
@Directive({
selector: 'ov-videoconference[participantName]'
})
export class ParticipantNameDirective implements OnInit {
// Avoiding update participantName dynamically.
// The participantName must be updated from UI
/**
* @ignore
*/
@Input() participantName: string;
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
/**
* @ignore
*/
ngOnInit(): void {
this.update(this.participantName);
}
/**
* @ignore
*/
ngOnDestroy(): void {
this.clear();
}
/**
* @ignore
*/
clear() {
this.update('');
}
/**
* @ignore
*/
update(value: string) {
this.libService.participantName.next(value);
}
}
/**
* The **prejoin** directive allows show/hide the prejoin page for selecting media devices.
*
* It is only available for {@link VideoconferenceComponent}.
*
* Default: `true`
*
* @example
* <ov-videoconference [prejoin]="false"></ov-videoconference>
*/
@Directive({
selector: 'ov-videoconference[prejoin]'
})
export class PrejoinDirective implements OnDestroy {
/**
* @ignore
*/
@Input() set prejoin(value: boolean) {
this.update(value);
}
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
/**
* @ignore
*/
ngOnDestroy(): void {
this.clear();
}
/**
* @ignore
*/
clear() {
this.update(true);
}
/**
* @ignore
*/
update(value: boolean) {
if (this.libService.prejoin.getValue() !== value) {
this.libService.prejoin.next(value);
@ -68,20 +154,50 @@ export class PrejoinDirective implements OnDestroy {
}
}
/**
* The **videoMuted** directive allows to join the session with camera muted/unmuted.
*
* It is only available for {@link VideoconferenceComponent}.
*
* Default: `false`
*
*
* @example
* <ov-videoconference [videoMuted]="true"></ov-videoconference>
*/
@Directive({
selector: 'ov-videoconference[videoMuted]'
})
export class VideoMutedDirective implements OnDestroy {
/**
* @ignore
*/
@Input() set videoMuted(value: boolean) {
this.update(value);
}
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
/**
* @ignore
*/
ngOnDestroy(): void {
this.clear();
}
/**
* @ignore
*/
clear() {
this.update(false);
}
/**
* @ignore
*/
update(value: boolean) {
if (this.libService.videoMuted.getValue() !== value) {
this.libService.videoMuted.next(value);
@ -89,21 +205,48 @@ export class VideoMutedDirective implements OnDestroy {
}
}
/**
* The **audioMuted** directive allows to join the session with microphone muted/unmuted.
*
* It is only available for {@link VideoconferenceComponent}.
*
* Default: `false`
*
* @example
* <ov-videoconference [audioMuted]="true"></ov-videoconference>
*/
@Directive({
selector: 'ov-videoconference[audioMuted]'
})
export class AudioMutedDirective implements OnDestroy {
/**
* @ignore
*/
@Input() set audioMuted(value: boolean) {
this.update(value);
}
/**
* @ignore
*/
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
ngOnDestroy(): void {
this.clear();
}
/**
* @ignore
*/
clear() {
this.update(false);
}
/**
* @ignore
*/
update(value: boolean) {
if (this.libService.audioMuted.getValue() !== value) {
this.libService.audioMuted.next(value);

View File

@ -1,19 +1,71 @@
import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';
/**
* The ***ovToolbar** directive allows to replace the default toolbar component injecting your custom template.
*
* @example
* <my-custom-toolbar *ovToolbar></my-custom-toolbar>
*
*/
@Directive({
selector: '[ovToolbar]'
})
export class ToolbarDirective {
/**
* @ignore
*/
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
/**
* The ***ovToolbarAdditionalButtons** directive allows to add additional buttons to the toolbar.
* There are two ways to use this directive:
*
* 1. Adding it to an element as a child of the parent element **_ov-videoconference_** {@link VideoconferenceComponent}
* @example
* <ov-videoconference>
* <div *ovToolbarAdditionalButtons>
* <button>Additional button</button>
* <button>Click Me</button>
* </div>
* </ov-videoconference>
*
* <br>
* 2. Adding it to an element as child of the element tagged with the {@link ToolbarDirective}
* @example
* <ov-videoconference>
* <my-toolbar *ovToolbar>
* <div *ovToolbarAdditionalButtons>
* <button>Additional button</button>
* <button>Click Me</button>
* </div>
* </my-toolbar>
* </ov-videoconference>
*
*/
@Directive({
selector: '[ovToolbarAdditionalButtons]'
})
export class ToolbarAdditionalButtonsDirective {
/**
* @ignore
*/
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
/**
* The ***ovPanel** directive allows to replace the default panel component injecting your custom template.
*
* This directive is closely related to {@link ChatPanelDirective} and {@link ParticipantsPanelDirective}.
*
*
* @example
* <my-custom-panel *ovPanel>
* ...
* </my-custom-panel>
*
*/
@Directive({
selector: '[ovPanel]'
})
@ -21,6 +73,32 @@ export class PanelDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
/**
* The ***ovChatPanel** directive allows to replace the defaultchat panel template injecting your own component.
* There are two ways to use this directive:
*
* 1. Adding it to an element as a child of the parent element **_ov-videoconference_** {@link VideoconferenceComponent}
* @example
* <ov-videoconference>
* <my-chat-panel *ovChatPanel></my-chat-panel>
* </ov-videoconference>
*
* <br>
* 2. Adding it to an element as child of the element tagged with the {@link ToolbarDirective}
* @example
* <ov-videoconference>
* <my-panel *ovPanel>
* <my-chat-panel *ovChatPanel></my-chat-panel>
* </my-panel>
* </ov-videoconference>
*
* <div class="info-container">
* <span>INFO:</span>
* You also can use the default components adsada dasda d asd
* </div>
*
*/
@Directive({
selector: '[ovChatPanel]'
})
@ -56,10 +134,37 @@ export class LayoutDirective {
constructor(public template: TemplateRef<any>, public container: ViewContainerRef) {}
}
/**
* The ***ovStream** directive allows to replace the default stream component template injecting your own component.
* There are two ways to use this directive:
*
* 1. Adding it to an element as a child of the parent element **_ov-videoconference_** {@link VideoconferenceComponent}
* @example
* <ov-videoconference>
*
*
* <my-chat-panel *ovChatPanel></my-chat-panel>
* </ov-videoconference>
*
* <br>
* 2. Adding it to an element as child of the element tagged with the {@link ToolbarDirective}
* @example
* <ov-videoconference>
* <my-panel *ovPanel>
* <my-chat-panel *ovChatPanel></my-chat-panel>
* </my-panel>
* </ov-videoconference>
*
* <div class="info-container">
* <span>INFO:</span>
* You also can use the default components adsada dasda d asd
* </div>
*
*/
@Directive({
selector: '[ovStream]'
})
export class StreamDirective {
constructor(public template: TemplateRef<any>, public container: ViewContainerRef) {}
}

View File

@ -2,6 +2,9 @@ import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
/** Error when invalid control is dirty, touched, or submitted. */
/**
* @internal
*/
export class NicknameMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;

View File

@ -1,8 +1,6 @@
export enum AvatarType {
DEFAULT = 'default',
CAPTURED = 'captured'
}
/**
* @internal
*/
export interface ChatMessage {
isLocal: boolean;
nickname: string;

View File

@ -1,15 +1,24 @@
/**
* @internal
*/
export interface CustomDevice {
label: string;
device: string;
type?: CameraType;
}
/**
* @internal
*/
export enum CameraType {
FRONT = 'FRONT',
BACK = 'BACK'
}
/**
* @internal
*/
export enum DeviceType {
AUDIO_INPUT = 'audioinput',
VIDEO_INPUT = 'videoinput'
}
}

View File

@ -1,3 +1,6 @@
/**
* @internal
*/
export enum VideoSizeIcon {
BIG = 'zoom_in',
NORMAL = 'zoom_out'

View File

@ -1,3 +1,6 @@
/**
* @internal
*/
export enum LayoutClass {
ROOT_ELEMENT = 'OT_root',
BIG_ELEMENT = 'OV_big',
@ -6,15 +9,17 @@ export enum LayoutClass {
NO_SIZE_ELEMENT = 'no-size'
}
/**
* @internal
*/
export enum SidenavMode {
OVER = 'over',
SIDE = 'side'
}
/**
* @hidden
* @internal
*/
export interface OpenViduLayoutOptions {
/**
* The narrowest ratio that will be used (*2x3* by default)
@ -70,6 +75,9 @@ export interface OpenViduLayoutOptions {
bigFirst: any;
}
/**
* @internal
*/
export class OpenViduLayout {
/**
* @hidden

View File

@ -1,5 +1,8 @@
import { Autolinker, AutolinkerConfig, HashtagMatch } from 'autolinker';
/**
* @internal
*/
const AUTOLINKER_CFGS: AutolinkerConfig = {
urls: {
schemeMatches: true,
@ -20,6 +23,9 @@ const AUTOLINKER_CFGS: AutolinkerConfig = {
decodePercentEncoding: true
};
/**
* @internal
*/
export class Linkifier {
private autolinker: Autolinker;

View File

@ -1,9 +1,15 @@
/**
* @internal
*/
export interface ILogger {
d(...args: any[]): void;
w(...args: any[]): void;
e(...args: any[]): void;
}
/**
* @internal
*/
export interface ILogService {
get(name: string): ILogger;
}

View File

@ -1,3 +1,6 @@
/**
* @internal
*/
export enum MenuType {
CHAT = 'chat',
PARTICIPANTS = 'participants'

View File

@ -1,5 +1,8 @@
import { MatSnackBarConfig } from '@angular/material/snack-bar';
/**
* @internal
*/
export interface INotificationOptions {
message: string;
buttonActionText?: string;

View File

@ -2,19 +2,52 @@ import { Publisher, StreamManager } from 'openvidu-browser';
import { VideoType } from './video-type.model';
export interface StreamModel {
/**
* Whether the stream is available or not
*/
connected: boolean;
/**
* The stream type.{@link VideoType}
*/
type: VideoType;
/**
* The streamManager object from openvidu-browser library.{@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/StreamManager.html}
*/
streamManager: StreamManager;
/**
* Whether the stream is enlarged or not
*/
videoEnlarged: boolean;
/**
* Unique identifier of the stream
*/
connectionId: string;
participant?: ParticipantAbstractModel
/**
* The participant object
*/
participant?: ParticipantAbstractModel;
}
export interface ParticipantProperties {
/**
* Whether the participant is local or not
*/
local: boolean;
/**
* The participant nickname
*/
nickname: string;
/**
* Unique identifier of the participant
*/
id?: string;
/**
* The participant color profile
*/
colorProfile?: string;
/**
* Whether the participant is muted forcibly or not
*/
isMutedForcibly?: boolean;
}
@ -30,7 +63,7 @@ export abstract class ParticipantAbstractModel {
this.id = props.id ? props.id : new Date().getTime().toString();
this.local = props.local;
this.nickname = props.nickname;
this.colorProfile = !!props.colorProfile ? props.colorProfile : `hsl(${Math.random()*360}, 100%, 80%)`;
this.colorProfile = !!props.colorProfile ? props.colorProfile : `hsl(${Math.random() * 360}, 100%, 80%)`;
this.isMutedForcibly = typeof props.isMutedForcibly === 'boolean' ? props.isMutedForcibly : false;
let streamModel: StreamModel = {
connected: model ? model.connected : true,
@ -43,43 +76,68 @@ export abstract class ParticipantAbstractModel {
this.streams.set(streamModel.type, streamModel);
}
/**
* @internal
*/
addConnection(streamModel: StreamModel) {
streamModel.participant = this;
this.streams.set(streamModel.type, streamModel);
}
/**
* @internal
*/
public isCameraAudioActive(): boolean {
const cameraConnection = this.getCameraConnection();
if(cameraConnection) {
if (cameraConnection) {
return cameraConnection.connected && cameraConnection.streamManager?.stream?.audioActive;
}
return this.isScreenAudioActive();;
return this.isScreenAudioActive();
}
/**
* @internal
*/
public isCameraVideoActive(): boolean {
const cameraConnection = this.getCameraConnection();
return cameraConnection?.connected && cameraConnection?.streamManager?.stream?.videoActive;
}
/**
* @internal
*/
isScreenAudioActive(): boolean {
const screenConnection = this.getScreenConnection();
if(screenConnection){
if (screenConnection) {
return screenConnection?.connected && screenConnection?.streamManager?.stream?.audioActive;
}
return false;
}
/**
* @internal
*/
hasConnectionType(type: VideoType): boolean {
return this.streams.has(type);
}
/**
* @internal
*/
public getCameraConnection(): StreamModel {
return this.streams.get(VideoType.CAMERA);
}
/**
* @internal
*/
public getScreenConnection(): StreamModel {
return this.streams.get(VideoType.SCREEN);
}
/**
* @internal
*/
getConnectionTypesActive(): VideoType[] {
let connType = [];
if (this.isCameraActive()) connType.push(VideoType.CAMERA);
@ -88,116 +146,168 @@ export abstract class ParticipantAbstractModel {
return connType;
}
/**
* @internal
*/
setCameraConnectionId(connectionId: string) {
this.getCameraConnection().connectionId = connectionId;
}
/**
* @internal
*/
setScreenConnectionId(connectionId: string) {
this.getScreenConnection().connectionId = connectionId;
}
/**
* @internal
*/
removeConnection(connectionId: string): StreamModel {
const removeStream = this.getConnectionById(connectionId);
this.streams.delete(removeStream.type);
return removeStream;
}
/**
* @internal
*/
hasConnectionId(connectionId: string): boolean {
return Array.from(this.streams.values()).some((conn) => conn.connectionId === connectionId);
}
/**
* @internal
*/
getConnectionById(connectionId: string): StreamModel {
return Array.from(this.streams.values()).find((conn) => conn.connectionId === connectionId);
}
/**
* @internal
*/
getAvailableConnections(): StreamModel[] {
return Array.from(this.streams.values()).filter((conn) => conn.connected);
}
/**
* @internal
*/
isLocal(): boolean {
return this.local;
// return Array.from(this.streams.values()).every((conn) => conn.local);
}
/**
* @internal
*/
setNickname(nickname: string) {
this.nickname = nickname;
// this.streams.forEach((conn) => {
// if (conn.type === VideoType.CAMERA) {
// conn.nickname = nickname;
// } else {
// conn.nickname = `${nickname}_${conn.type}`;
// }
// });
}
/**
* @internal
*/
getNickname() {
return this.nickname;
}
// getCameraNickname(): string {
// return this.getCameraConnection()?.nickname;
// }
// getScreenNickname(): string {
// return this.getScreenConnection()?.nickname;
// }
/**
* @internal
*/
setCameraPublisher(publisher: Publisher) {
const cameraConnection = this.getCameraConnection();
if (cameraConnection) cameraConnection.streamManager = publisher;
}
/**
* @internal
*/
setScreenPublisher(publisher: Publisher) {
const screenConnection = this.getScreenConnection();
if (screenConnection) screenConnection.streamManager = publisher;
}
/**
* @internal
*/
setPublisher(connType: VideoType, publisher: StreamManager) {
const connection = this.streams.get(connType);
if(connection) {
if (connection) {
connection.streamManager = publisher;
}
}
/**
* @internal
*/
isCameraActive(): boolean {
return this.getCameraConnection()?.connected;
}
/**
* @internal
*/
enableCamera() {
const cameraConnection = this.getCameraConnection();
if (cameraConnection) cameraConnection.connected = true;
}
/**
* @internal
*/
disableCamera() {
const cameraConnection = this.getCameraConnection();
if (cameraConnection) cameraConnection.connected = false;
}
/**
* @internal
*/
isScreenActive(): boolean {
return this.getScreenConnection()?.connected;
}
/**
* @internal
*/
enableScreen() {
const screenConnection = this.getScreenConnection();
if (screenConnection) screenConnection.connected = true;
}
/**
* @internal
*/
disableScreen() {
const screenConnection = this.getScreenConnection();
if (screenConnection) screenConnection.connected = false;
}
/**
* @internal
*/
setAllVideoEnlarged(enlarged: boolean) {
this.streams.forEach((conn) => (conn.videoEnlarged = enlarged));
}
/**
* @internal
*/
setCameraEnlarged(enlarged: boolean) {
this.streams.get(VideoType.CAMERA).videoEnlarged = enlarged;
}
/**
* @internal
*/
setScreenEnlarged(enlarged: boolean) {
this.streams.get(VideoType.SCREEN).videoEnlarged = enlarged;
}
/**
* @internal
*/
toggleVideoEnlarged(connectionId: string) {
this.streams.forEach((conn) => {
if (conn.connectionId === connectionId) {
@ -206,17 +316,22 @@ export abstract class ParticipantAbstractModel {
});
}
/**
* @internal
*/
someHasVideoEnlarged(): boolean {
return Array.from(this.streams.values()).some((conn) => conn.videoEnlarged);
}
setMutedForcibly(muted: boolean){
/**
* @internal
*/
setMutedForcibly(muted: boolean) {
this.isMutedForcibly = muted;
}
}
export class ParticipantModel extends ParticipantAbstractModel {
}
/**
* @internal
*/
export class ParticipantModel extends ParticipantAbstractModel {}

View File

@ -1,3 +1,6 @@
/**
* @internal
*/
export enum Signal {
NICKNAME_CHANGED = 'nicknameChanged',
CHAT = 'chat'

View File

@ -1,3 +1,6 @@
/**
* @internal
*/
export enum Storage{
USER_NICKNAME = 'openviduCallNickname',
VIDEO_DEVICE = 'openviduCallVideoDevice',

View File

@ -0,0 +1,7 @@
/**
* @internal
*/
export interface TokenModel {
webcam: string;
screen: string;
}

View File

@ -4,6 +4,9 @@ export enum VideoType {
CUSTOM = 'CUSTOM'
}
/**
* @internal
*/
export enum ScreenType {
WINDOW = 'window',
SCREEN = 'screen'

View File

@ -1,13 +0,0 @@
import { ISettings } from './settings.model';
export interface ISessionConfig {
sessionName: string;
user: string;
tokens: string[];
ovSettings: ISettings;
}
export enum Theme {
DARK = 'dark',
LIGHT = 'light'
}

View File

@ -1,6 +1,9 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Linkifier } from '../models/linkifier.model';
/**
* @internal
*/
@Pipe({ name: 'linkify' })
export class LinkifyPipe implements PipeTransform {
private linkifer: Linkifier;

View File

@ -1,6 +1,9 @@
import { Pipe, PipeTransform } from '@angular/core';
import { StreamModel, ParticipantAbstractModel } from '../models/participant.model';
/**
* @internal
*/
@Pipe({ name: 'streams' })
export class ParticipantStreamsPipe implements PipeTransform {
constructor() {}
@ -21,6 +24,9 @@ export class ParticipantStreamsPipe implements PipeTransform {
}
}
/**
* @internal
*/
@Pipe({ name: 'streamTypesEnabled' })
export class StreamTypesEnabledPipe implements PipeTransform {
constructor() {}

View File

@ -5,6 +5,9 @@ import { DialogTemplateComponent } from '../../components/material/dialog.compon
import { INotificationOptions } from '../../models/notification-options.model';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -1,5 +1,9 @@
import { Injectable } from '@angular/core';
import {CdkOverlayContainer } from '../../config/custom-cdk-overlay';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -14,6 +14,9 @@ import { SidenavMenuService } from '../sidenav-menu/sidenav-menu.service';
import { ParticipantService } from '../participant/participant.service';
import { MenuType } from '../../models/menu.model';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -4,7 +4,9 @@ import { OpenViduAngularConfig, ParticipantFactoryFunction } from '../../config/
// import { version } from '../../../../package.json';
/**
* @internal
*/
@Injectable()
export class OpenViduAngularConfigService {
private configuration: OpenViduAngularConfig;
@ -51,7 +53,7 @@ export class OpenViduAngularConfigService {
constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) {
this.configuration = config;
console.log(this.configuration);
if(this.isProduction()) console.log('OpenVidu Angular Production Mode');
if (this.isProduction()) console.log('OpenVidu Angular Production Mode');
this.minimalObs = this.minimal.asObservable();
this.participantNameObs = this.participantName.asObservable();
this.prejoinObs = this.prejoin.asObservable();
@ -85,7 +87,7 @@ export class OpenViduAngularConfigService {
// }
hasParticipantFactory(): boolean {
return typeof this.getConfig().participantFactory === "function";
return typeof this.getConfig().participantFactory === 'function';
}
getParticipantFactory(): ParticipantFactoryFunction {

View File

@ -1,13 +1,13 @@
import { Injectable } from '@angular/core';
import { CameraType, IDevice } from '../../models/device.model';
import { CameraType, CustomDevice } from '../../models/device.model';
@Injectable()
export class DeviceServiceMock {
audioDevice: IDevice = {
audioDevice: CustomDevice = {
label: 'audio',
device: 'mockDevice'
};
videodevice: IDevice = {
videodevice: CustomDevice = {
label: 'video',
device: 'mockDevice',
type: CameraType.FRONT
@ -17,11 +17,11 @@ export class DeviceServiceMock {
async initDevices() {}
getCamSelected(): IDevice {
getCamSelected(): CustomDevice {
return this.videodevice;
}
getMicSelected(): IDevice {
getMicSelected(): CustomDevice {
return this.audioDevice;
}
@ -37,11 +37,11 @@ export class DeviceServiceMock {
return false;
}
getCameras(): IDevice[] {
getCameras(): CustomDevice[] {
return [this.videodevice];
}
getMicrophones(): IDevice[] {
getMicrophones(): CustomDevice[] {
return [this.audioDevice];
}

View File

@ -9,6 +9,9 @@ import { LoggerService } from '../logger/logger.service';
import { PlatformService } from '../platform/platform.service';
import { StorageService } from '../storage/storage.service';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})
@ -60,7 +63,7 @@ export class DeviceService {
this.microphones = customDevices.microphones;
this._isVideoMuted = this.storageSrv.isVideoMuted() || this.libSrv.videoMuted.getValue();
this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue();;
this._isAudioMuted = this.storageSrv.isAudioMuted() || this.libSrv.audioMuted.getValue();
this.log.d('Media devices', customDevices);
}

View File

@ -1,6 +1,9 @@
import { Injectable } from '@angular/core';
import { LayoutClass } from '../../models/layout.model';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -3,6 +3,9 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { LayoutClass, OpenViduLayout, OpenViduLayoutOptions } from '../../models/layout.model';
import { DocumentService } from '../document/document.service';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -3,6 +3,9 @@ import { ILogService } from '../../models/logger.model';
import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.service';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -33,6 +33,9 @@ export class OpenViduService {
protected audioSource = undefined;
protected log: ILogger;
/**
* @internal
*/
constructor(
protected openviduAngularConfigSrv: OpenViduAngularConfigService,
protected platformService: PlatformService,
@ -43,6 +46,9 @@ export class OpenViduService {
this.log = this.loggerSrv.get('OpenViduService');
}
/**
* @internal
*/
initialize() {
this.OV = new OpenVidu();
if (this.openviduAngularConfigSrv.isProduction()) this.OV.enableProdMode();
@ -60,22 +66,37 @@ export class OpenViduService {
return this.getWebcamSession();
}
/**
* @internal
*/
getWebcamSession(): Session {
return this.webcamSession;
}
/**
* @internal
*/
isWebcamSessionConnected(): boolean {
return !!this.webcamSession.capabilities;
}
/**
* @internal
*/
getScreenSession(): Session {
return this.screenSession;
}
/**
* @internal
*/
isScreenSessionConnected(): boolean {
return !!this.screenSession.capabilities;
}
/**
* @internal
*/
async connectSession(session: Session, token: string): Promise<void> {
if (!!token && session) {
const nickname = this.participantService.getMyNickname();
@ -101,6 +122,9 @@ export class OpenViduService {
}
}
/**
* @internal
*/
disconnect() {
this.disconnectSession(this.webcamSession);
this.disconnectSession(this.screenSession);
@ -111,6 +135,7 @@ export class OpenViduService {
}
/**
* @internal
* Initialize a publisher checking devices saved on storage or if participant have devices available.
*/
async initDefaultPublisher(targetElement: string | HTMLElement): Promise<Publisher> {
@ -158,11 +183,17 @@ export class OpenViduService {
}
}
/**
* @internal
*/
async initPublisher(targetElement: string | HTMLElement, properties: PublisherProperties): Promise<Publisher> {
this.log.d('Initializing publisher with properties: ', properties);
return await this.OV.initPublisherAsync(targetElement, properties);
}
/**
* @internal
*/
async publish(publisher: Publisher): Promise<void> {
if (!!publisher) {
if (publisher === this.participantService.getMyCameraPublisher()) {
@ -179,6 +210,9 @@ export class OpenViduService {
}
}
/**
* @internal
*/
unpublish(publisher: Publisher): void {
if (!!publisher) {
if (publisher === this.participantService.getMyCameraPublisher()) {
@ -190,6 +224,9 @@ export class OpenViduService {
}
}
/**
* @internal
*/
publishVideo(publisher: Publisher, value: boolean): void {
if (!!publisher) {
publisher.publishVideo(value);
@ -197,6 +234,9 @@ export class OpenViduService {
}
}
/**
* @internal
*/
publishAudio(publisher: Publisher, value: boolean): void {
if (!!publisher) {
publisher.publishAudio(value);
@ -204,8 +244,11 @@ export class OpenViduService {
}
}
// TODO: Remove this method when replaceTrack issue is fixed
// https://github.com/OpenVidu/openvidu/pull/700
/**
* TODO: Remove this method when replaceTrack issue is fixed
* https://github.com/OpenVidu/openvidu/pull/700
* @internal
*/
republishTrack(properties: PublisherProperties): Promise<void> {
const { videoSource, audioSource, mirror } = properties;
return new Promise(async (resolve, reject) => {
@ -240,6 +283,9 @@ export class OpenViduService {
});
}
/**
* @internal
*/
sendSignal(type: Signal, connections?: Connection[], data?: any): void {
const signalOptions: SignalOptions = {
data: JSON.stringify(data),
@ -255,6 +301,9 @@ export class OpenViduService {
// }
}
/**
* @internal
*/
async replaceTrack(videoType: VideoType, props: PublisherProperties) {
try {
this.log.d(`Replacing ${videoType} track`, props);
@ -346,6 +395,9 @@ export class OpenViduService {
}
}
/**
* @internal
*/
needSendNicknameSignal(): boolean {
let oldNickname: string;
try {
@ -357,6 +409,9 @@ export class OpenViduService {
return oldNickname !== this.participantService.getMyNickname();
}
/**
* @internal
*/
isMyOwnConnection(connectionId: string): boolean {
return (
this.webcamSession?.connection?.connectionId === connectionId || this.screenSession?.connection?.connectionId === connectionId

View File

@ -1,17 +1,17 @@
import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { Publisher } from 'openvidu-browser/lib/OpenVidu/Publisher';
import { UserModel } from '../../models/user.model';
import { ParticipantAbstractModel } from '../../models/participant.model';
@Injectable({
providedIn: 'root'
})
export class ParticipantServiceMock {
OVUsers: Observable<UserModel[]>;
OVUsers: Observable<ParticipantAbstractModel[]>;
screenShareState: Observable<boolean>;
webcamVideoActive: Observable<boolean>;
private _OVUsers = <BehaviorSubject<UserModel[]>>new BehaviorSubject([]);
private _OVUsers = <BehaviorSubject<ParticipantAbstractModel[]>>new BehaviorSubject([]);
private _screenShareState = <BehaviorSubject<boolean>>new BehaviorSubject(false);
private _webcamVideoActive = <BehaviorSubject<boolean>>new BehaviorSubject(true);

View File

@ -11,11 +11,17 @@ import { LoggerService } from '../logger/logger.service';
providedIn: 'root'
})
export class ParticipantService {
//Local participants observables
/**
* @internal
* Local participants observables
*/
localParticipantObs: Observable<ParticipantAbstractModel>;
protected _localParticipant = <BehaviorSubject<ParticipantAbstractModel>>new BehaviorSubject(null);
//Remote participants observable
/**
* @internal
* Remote participants observables
*/
remoteParticipantsObs: Observable<ParticipantAbstractModel[]>;
protected _remoteParticipants = <BehaviorSubject<ParticipantAbstractModel[]>>new BehaviorSubject([]);
@ -24,6 +30,9 @@ export class ParticipantService {
protected log: ILogger;
/**
* @internal
*/
constructor(protected openviduAngularConfigSrv: OpenViduAngularConfigService, protected loggerSrv: LoggerService) {
this.log = this.loggerSrv.get('ParticipantService');
@ -31,7 +40,10 @@ export class ParticipantService {
this.remoteParticipantsObs = this._remoteParticipants.asObservable();
}
initLocalParticipant(props: ParticipantProperties) {
/**
* @internal
*/
initLocalParticipant(props: ParticipantProperties) {
this.localParticipant = this.newParticipant(props);
this.updateLocalParticipant();
}
@ -40,13 +52,22 @@ export class ParticipantService {
return this.localParticipant;
}
/**
* @internal
*/
getMyCameraPublisher(): Publisher {
return <Publisher>this.localParticipant.getCameraConnection().streamManager;
}
/**
* @internal
*/
setMyCameraPublisher(publisher: Publisher) {
this.localParticipant.setCameraPublisher(publisher);
}
/**
* @internal
*/
setMyCameraConnectionId(connectionId: string) {
this.localParticipant.setCameraConnectionId(connectionId);
}
@ -58,26 +79,39 @@ export class ParticipantService {
return <Publisher>this.localParticipant.getScreenConnection()?.streamManager;
}
/**
* @internal
*/
setMyScreenPublisher(publisher: Publisher) {
this.localParticipant.setScreenPublisher(publisher);
}
/**
* @internal
*/
setMyScreenConnectionId(connectionId: string) {
this.localParticipant.setScreenConnectionId(connectionId);
}
/**
* @internal
*/
enableWebcamStream() {
this.localParticipant.enableCamera();
this.updateLocalParticipant();
}
/**
* @internal
*/
disableWebcamStream() {
this.localParticipant.disableCamera();
this.updateLocalParticipant();
}
/**
* @internal
*/
activeMyScreenShare(screenPublisher: Publisher) {
this.log.d('Enabling screen publisher');
@ -96,16 +130,24 @@ export class ParticipantService {
}
/**
* @internal
*/
disableScreenStream() {
this.localParticipant.disableScreen();
this.updateLocalParticipant();
}
/**
* @internal
*/
setMyNickname(nickname: string) {
this.localParticipant.setNickname(nickname);
this.updateLocalParticipant();
}
/**
* @internal
*/
getMyNickname(): string {
return this.localParticipant.nickname;
}
@ -113,13 +155,13 @@ export class ParticipantService {
/**
* @internal
*/
toggleMyVideoEnlarged(connectionId: string) {
this.localParticipant.toggleVideoEnlarged(connectionId);
}
/**
* @internal
*/
resetMyStreamsToNormalSize() {
if (this.localParticipant.someHasVideoEnlarged()) {
this.localParticipant.setAllVideoEnlarged(false);
@ -127,6 +169,9 @@ export class ParticipantService {
}
}
/**
* @internal
*/
clear() {
this.disableScreenStream();
// this.localParticipant = this.newParticipant();
@ -137,34 +182,58 @@ export class ParticipantService {
this.updateLocalParticipant();
}
/**
* @internal
*/
isMyCameraActive(): boolean {
return this.localParticipant.isCameraActive();
}
/**
* @internal
*/
isMyScreenActive(): boolean {
return this.localParticipant.isScreenActive();
}
/**
* @internal
*/
isOnlyMyCameraActive(): boolean {
return this.isMyCameraActive() && !this.isMyScreenActive();
}
/**
* @internal
*/
isOnlyMyScreenActive(): boolean {
return this.isMyScreenActive() && !this.isMyCameraActive();
}
/**
* @internal
*/
haveICameraAndScreenActive(): boolean {
return this.isMyCameraActive() && this.isMyScreenActive();
}
/**
* @internal
*/
hasCameraVideoActive(): boolean {
return this.localParticipant.isCameraVideoActive();
}
/**
* @internal
*/
hasCameraAudioActive(): boolean {
return this.localParticipant?.isCameraAudioActive();
}
/**
* @internal
*/
hasScreenAudioActive(): boolean {
return this.localParticipant.isScreenAudioActive();
}
@ -177,14 +246,16 @@ export class ParticipantService {
* REMOTE USERS
*/
addRemoteConnection(connectionId:string, data: string, subscriber: Subscriber) {
/**
* @internal
*/
addRemoteConnection(connectionId: string, data: string, subscriber: Subscriber) {
const type: VideoType = this.getTypeConnectionData(data);
const streamModel: StreamModel = {
type,
videoEnlarged: type === VideoType.SCREEN,
streamManager: subscriber,
connected: true,
connected: true,
connectionId
};
@ -195,12 +266,12 @@ export class ParticipantService {
const participantAdded = this.getRemoteParticipantById(participantId);
if (!!participantAdded) {
this.log.d('Adding connection to existing participant: ', participantId);
if(participantAdded.hasConnectionType(streamModel.type)) {
if (participantAdded.hasConnectionType(streamModel.type)) {
this.log.d('Participant has publisher, updating it');
participantAdded.setPublisher(streamModel.type, subscriber);
} else {
this.log.d('Participant has not publisher, adding it');
if(streamModel.type === VideoType.SCREEN) {
if (streamModel.type === VideoType.SCREEN) {
this.resetRemoteStreamsToNormalSize();
this.resetMyStreamsToNormalSize();
}
@ -212,18 +283,28 @@ export class ParticipantService {
nickname: this.getNicknameFromConnectionData(data),
local: false,
id: participantId
}
};
const remoteParticipant = this.newParticipant(props, streamModel);
this.remoteParticipants.push(remoteParticipant);
}
this.updateRemoteParticipants();
}
getRemoteParticipants(): ParticipantAbstractModel[] {
return this.remoteParticipants;
}
/**
* @internal
*/
resetRemoteStreamsToNormalSize() {
this.remoteParticipants.forEach(participant => participant.setAllVideoEnlarged(false));
this.remoteParticipants.forEach((participant) => participant.setAllVideoEnlarged(false));
this.updateRemoteParticipants();
}
/**
* @internal
*/
removeConnectionByConnectionId(connectionId: string) {
this.log.w('Deleting connection: ', connectionId);
let participant = null;
@ -240,13 +321,13 @@ export class ParticipantService {
// Remove participants without connections
this.remoteParticipants = this.remoteParticipants.filter((p) => p !== participant);
}
if(removeStream.type === VideoType.SCREEN){
const remoteScreens = this.remoteParticipants.filter(p => p.isScreenActive());
if(remoteScreens.length > 0){
if (removeStream.type === VideoType.SCREEN) {
const remoteScreens = this.remoteParticipants.filter((p) => p.isScreenActive());
if (remoteScreens.length > 0) {
// Enlarging the last screen connection active
const lastScreenActive = remoteScreens[remoteScreens.length -1];
const lastScreenActive = remoteScreens[remoteScreens.length - 1];
lastScreenActive.setScreenEnlarged(true);
} else if(this.localParticipant.isScreenActive()) {
} else if (this.localParticipant.isScreenActive()) {
// Enlarging my screen if thereare not any remote screen active
this.localParticipant.setScreenEnlarged(true);
}
@ -255,6 +336,9 @@ export class ParticipantService {
this.updateRemoteParticipants();
}
}
/**
* @internal
*/
getRemoteParticipantByConnectionId(connectionId: string): ParticipantAbstractModel {
return this.remoteParticipants.find((p) => p.hasConnectionId(connectionId));
}
@ -262,15 +346,24 @@ export class ParticipantService {
protected getRemoteParticipantById(id: string): ParticipantAbstractModel {
return this.remoteParticipants.find((p) => p.id === id);
}
/**
* @internal
*/
someoneIsSharingScreen(): boolean {
return this.remoteParticipants.some((p) => p.someHasVideoEnlarged());
}
/**
* @internal
*/
toggleRemoteVideoEnlarged(connectionId: string) {
const p = this.getRemoteParticipantByConnectionId(connectionId);
p.toggleVideoEnlarged(connectionId);
}
/**
* @internal
*/
getNicknameFromConnectionData(data: string): string {
try {
return JSON.parse(data).clientData;
@ -279,6 +372,9 @@ export class ParticipantService {
}
}
/**
* @internal
*/
setRemoteNickname(connectionId: string, nickname: string) {
const participant = this.getRemoteParticipantByConnectionId(connectionId);
if (participant) {
@ -308,8 +404,7 @@ export class ParticipantService {
}
protected newParticipant(props: ParticipantProperties, streamModel?: StreamModel) {
if(this.openviduAngularConfigSrv.hasParticipantFactory()){
if (this.openviduAngularConfigSrv.hasParticipantFactory()) {
return this.openviduAngularConfigSrv.getParticipantFactory().apply(this, [props, streamModel]);
}
return new ParticipantModel(props, streamModel);

View File

@ -1,5 +1,8 @@
import { Injectable } from '@angular/core';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -4,6 +4,9 @@ import { ILogger } from '../../models/logger.model';
import { MenuType } from '../../models/menu.model';
import { LoggerService } from '../logger/logger.service';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -3,6 +3,9 @@ import { ILogger } from '../../models/logger.model';
import { LoggerService } from '../logger/logger.service';
import { Storage } from '../../models/storage.model';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -1,5 +1,8 @@
import { Injectable } from '@angular/core';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})

View File

@ -0,0 +1,30 @@
<ov-videoconference
*ngIf="success"
[participantName]="_participantName"
[tokens]="_tokens"
[minimal]="_minimal"
[prejoin]="_prejoin"
[videoMuted]="_videoMuted"
[audioMuted]="_audioMuted"
[toolbarScreenshareButton]="_toolbarScreenshareButton"
[toolbarFullscreenButton]="_toolbarFullscreenButton"
[toolbarLeaveButton]="_toolbarLeaveButton"
[toolbarChatPanelButton]="_toolbarChatPanelButton"
[toolbarParticipantsPanelButton]="_toolbarParticipantsPanelButton"
[toolbarDisplayLogo]="_toolbarDisplayLogo"
[toolbarDisplaySessionName]="_toolbarDisplaySessionName"
[streamDisplayParticipantName]="_streamDisplayParticipantName"
[streamDisplayAudioDetection]="_streamDisplayAudioDetection"
[streamSettingsButton]="_streamSettingsButton"
[participantPanelItemMuteButton]="_participantPanelItemMuteButton"
(onJoinButtonClicked)="_onJoinButtonClicked()"
(onToolbarLeaveButtonClicked)="_onToolbarLeaveButtonClicked()"
(onToolbarCameraButtonClicked)="_onToolbarCameraButtonClicked()"
(onToolbarMicrophoneButtonClicked)="_onToolbarMicrophoneButtonClicked()"
(onToolbarScreenshareButtonClicked)="_onToolbarScreenshareButtonClicked()"
(onToolbarParticipantsPanelButtonClicked)="_onToolbarParticipantsPanelButtonClicked()"
(onToolbarChatPanelButtonClicked)="_onToolbarChatPanelButtonClicked()"
(onToolbarFullscreenButtonClicked)="_onToolbarFullscreenButtonClicked()"
(onSessionCreated)="_onSessionCreated($event)"
(onParticipantCreated)="_onParticipantCreated($event)"
></ov-videoconference>

View File

@ -8,57 +8,81 @@ export interface TokenModel {
screen: string;
}
/**
*
* **OpenviduWebComponentComponent** is a wrapped of the {@link VideoconferenceComponent} which allows to generate and export the OpenVidu Webcomponent
*/
@Component({
template: `
<ov-videoconference
*ngIf="success"
[participantName]="_participantName"
[tokens]="_tokens"
[minimal]="_minimal"
[prejoin]="_prejoin"
[videoMuted]="_videoMuted"
[audioMuted]="_audioMuted"
[toolbarScreenshareButton]="_toolbarScreenshareButton"
[toolbarFullscreenButton]="_toolbarFullscreenButton"
[toolbarLeaveButton]="_toolbarLeaveButton"
[toolbarChatPanelButton]="_toolbarChatPanelButton"
[toolbarParticipantsPanelButton]="_toolbarParticipantsPanelButton"
[toolbarDisplayLogo]="_toolbarDisplayLogo"
[toolbarDisplaySessionName]="_toolbarDisplaySessionName"
[streamDisplayParticipantName]="_streamDisplayParticipantName"
[streamDisplayAudioDetection]="_streamDisplayAudioDetection"
[streamSettingsButton]="_streamSettingsButton"
[participantPanelItemMuteButton]="_participantPanelItemMuteButton"
(onJoinButtonClicked)="_onJoinButtonClicked()"
(onToolbarLeaveButtonClicked)="_onToolbarLeaveButtonClicked()"
(onToolbarCameraButtonClicked)="_onToolbarCameraButtonClicked()"
(onToolbarMicrophoneButtonClicked)="_onToolbarMicrophoneButtonClicked()"
(onToolbarScreenshareButtonClicked)="_onToolbarScreenshareButtonClicked()"
(onToolbarParticipantsPanelButtonClicked)="_onToolbarParticipantsPanelButtonClicked()"
(onToolbarChatPanelButtonClicked)="_onToolbarChatPanelButtonClicked()"
(onToolbarFullscreenButtonClicked)="_onToolbarFullscreenButtonClicked()"
(onSessionCreated)="_onSessionCreated($event)"
(onParticipantCreated)="_onParticipantCreated($event)"
></ov-videoconference>
`
templateUrl: './openvidu-webcomponent.component.html'
})
export class OpenviduWebComponentComponent implements OnInit {
/**
* @internal
*/
_tokens: TokenModel;
/**
* @internal
*/
_minimal: boolean = false;
/**
* @internal
*/
_participantName: string;
/**
* @internal
*/
_prejoin: boolean = true;
/**
* @internal
*/
_videoMuted: boolean = false;
/**
* @internal
*/
_audioMuted: boolean = false;
/**
* @internal
*/
_toolbarScreenshareButton: boolean = true;
/**
* @internal
*/
_toolbarFullscreenButton: boolean = true;
/**
* @internal
*/
_toolbarLeaveButton: boolean = true;
/**
* @internal
*/
_toolbarChatPanelButton: boolean = true;
/**
* @internal
*/
_toolbarParticipantsPanelButton: boolean = true;
/**
* @internal
*/
_toolbarDisplayLogo: boolean = true;
/**
* @internal
*/
_toolbarDisplaySessionName: boolean = true;
/**
* @internal
*/
_streamDisplayParticipantName: boolean = true;
/**
* @internal
*/
_streamDisplayAudioDetection: boolean = true;
/**
* @internal
*/
_streamSettingsButton: boolean = true;
/**
* @internal
*/
_participantPanelItemMuteButton: boolean = true;
@Input() set minimal(value: string | boolean) {
@ -122,9 +146,15 @@ export class OpenviduWebComponentComponent implements OnInit {
@Output() onSessionCreated = new EventEmitter<any>();
@Output() onParticipantCreated = new EventEmitter<any>();
/**
* @internal
*/
success: boolean = false;
private log: ILogger;
/**
* @internal
*/
constructor(private loggerService: LoggerService, private host: ElementRef, private openviduService: OpenViduService) {
this.log = this.loggerService.get('WebComponent');
this.host.nativeElement.leaveSession = this.leaveSession.bind(this);
@ -147,37 +177,68 @@ export class OpenviduWebComponentComponent implements OnInit {
}
}
/**
* @internal
*/
_onJoinButtonClicked() {
this.onJoinButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarLeaveButtonClicked() {
this.success = false;
this.onToolbarLeaveButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarCameraButtonClicked() {
this.onToolbarCameraButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarMicrophoneButtonClicked() {
this.onToolbarMicrophoneButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarScreenshareButtonClicked() {
this.onToolbarScreenshareButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarParticipantsPanelButtonClicked() {
this.onToolbarParticipantsPanelButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarChatPanelButtonClicked() {
this.onToolbarChatPanelButtonClicked.emit();
}
/**
* @internal
*/
_onToolbarFullscreenButtonClicked() {
this.onToolbarFullscreenButtonClicked.emit();
}
/**
* @internal
*/
_onSessionCreated(event: Session) {
this.onSessionCreated.emit(event);
}
/**
* @internal
*/
_onParticipantCreated(event: ParticipantAbstractModel) {
this.onParticipantCreated.emit(event);
}

View File

@ -0,0 +1,19 @@
{
"name": "OpenVidu Angular Documentation",
"output": "docs/openvidu-angular",
"hideGenerator": true,
"disableLifeCycleHooks": true,
"disableProtected": true,
"disableInternal": true,
"disablePrivate": true,
"disableCoverage": true,
"disableRoutesGraph": true,
"disableSourceCode": true,
"disableTemplateTab": true,
"disableDomTree": true,
"disableStyleTab": true,
"disableDependencies": true,
"theme": "gitbook",
"customFavicon": "src/favicon.ico",
"extTheme": "src/doc/"
}

View File

@ -0,0 +1,93 @@
@import "./reset.css";
@import "./bootstrap.min.css";
@import "./bootstrap-card.css";
@import "./prism.css";
@import "./ionicons.min.css";
@import "./compodoc.css";
@import "./tablesort.css";
.title {
font-weight: bold;
}
/* .getting-started {
display: none;
} */
.token.property, .token.tag, .token.constant, .token.symbol, .token.deleted {
color: rgb(0, 204, 255);
}
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted {
color: #d3ff7c;
}
.token.atrule, .token.attr-value, .token.function, .token.class-name {
color: rgb(255, 170, 72);
}
.italic {
font-style: italic;
}
.component-link-text {
padding-top: 5px;
text-align: center;
font-size: 14px;
}
div>p {
font-size: 16px;
}
code {
background-color: rgb(233, 245, 255);
font-weight: bold;
padding: 2px;
}
.directive section, .module-graph-container, .card-module>.card-block>p,
nav a[href*="license.html"],
nav a[href*="properties.html"],
nav a[href*="overview.html"],
nav a[href*="index.html"] {
display: none !important;
}
.card-module {
min-height: 0;
}
.custom-table-container {
display: flex;
}
.custom-table-container table {
margin: auto;
}
.custom-table-container>div {
padding: 10px;
}
.warn-container, .info-container {
display: table;
border-radius: 5px;
width: 100%;
margin-top: 30px;
margin-bottom: 25px;
padding: 5px 0 5px 0;
}
.info-container > span, .warn-container >span {
font-weight: bold;
padding-left: 5px;
}
.warn-container {
border: 2px solid #ffb600;
background-color: #FFFBF1;
}
.info-container {
border: 2px solid #0077ff;
background-color: #f1feff;
}

View File

@ -0,0 +1,14 @@
{
"include": [
"../../projects/openvidu-angular/src/lib/components/**/*.ts",
"../../projects/openvidu-angular/src/lib/directives/**/*.ts",
"../../projects/openvidu-angular/src/lib/services/**/*.ts",
"../../projects/openvidu-angular/src/lib/models/**/*.ts",
"../app/openvidu-webcomponent/openvidu-webcomponent.component.ts"
],
"exclude": [
"src/test.ts",
"../../projects/openvidu-angular/src/lib/**/*.mock.ts",
"../../projects/openvidu-angular/src/lib/**/*.spec.ts"
],
}