mirror of https://github.com/OpenVidu/openvidu.git
openvidu-components: Added recording
openvidu-components: Fixed recording directive namepull/732/head
parent
206a44d881
commit
44110a6246
|
@ -0,0 +1,24 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-delete-dialog',
|
||||
template: `
|
||||
<div mat-dialog-content>{{'PANEL.RECORDING.DELETE_QUESTION' | translate}}</div>
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="close()">CANCEL</button>
|
||||
<button mat-button cdkFocusInitial (click)="close(true)" id="delete-recording-confirm-btn">{{'PANEL.RECORDING.DELETE' | translate}}</button>
|
||||
</div>
|
||||
`,
|
||||
styles: [``]
|
||||
})
|
||||
export class DeleteDialogComponent {
|
||||
constructor(public dialogRef: MatDialogRef<DeleteDialogComponent>) {}
|
||||
|
||||
close(succsess = false) {
|
||||
this.dialogRef.close(succsess);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-recording-dialog',
|
||||
template: `
|
||||
<div mat-dialog-content>
|
||||
<video controls autoplay>
|
||||
<source [src]="src" [type]="type" />
|
||||
</video>
|
||||
</div>
|
||||
<div mat-dialog-actions *ngIf="data.showActionButtons" align="end">
|
||||
<button mat-button (click)="close()">{{ 'PANEL.CLOSE' | translate }}</button>
|
||||
</div>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
video {
|
||||
max-height: 64vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
`
|
||||
]
|
||||
})
|
||||
export class RecordingDialogComponent {
|
||||
src: string;
|
||||
type: string;
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<RecordingDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
this.src = data.src;
|
||||
this.type = data.type;
|
||||
}
|
||||
close() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
::ng-deep .mat-expansion-panel-header {
|
||||
padding: 0px 10px !important;
|
||||
height: 65px !important;
|
||||
}
|
||||
|
||||
::ng-deep .mat-list-base .mat-list-item .mat-list-item-content,
|
||||
|
@ -44,6 +45,7 @@
|
|||
|
||||
::ng-deep mat-expansion-panel .mat-expansion-panel-body {
|
||||
padding: 0px !important;
|
||||
min-height: 400px;
|
||||
}
|
||||
::ng-deep .mat-expansion-panel-header-description {
|
||||
flex-grow: 0 !important;
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
<div class="panel-container" id="activities-container" fxLayout="column" fxLayoutAlign="space-evenly none">
|
||||
<div class="panel-header-container" fxFlex="55px" fxLayoutAlign="start center">
|
||||
<h3 class="panel-title">Activities</h3>
|
||||
<button class="panel-close-button" mat-icon-button matTooltip="Close" (click)="close()">
|
||||
<button class="panel-close-button" mat-icon-button matTooltip="{{ 'PANEL.CLOSE' | translate }}" (click)="close()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="activities-body-container" fxFlex="75%" fxLayoutAlign="space-evenly none">
|
||||
<mat-accordion>
|
||||
<ov-recording-activity></ov-recording-activity>
|
||||
<ov-recording-activity
|
||||
*ngIf="showRecordingActivity"
|
||||
id="recording-activity"
|
||||
[expanded]="expandedPanel === 'recording'"
|
||||
(onStartRecordingClicked)="_onStartRecordingClicked()"
|
||||
(onStopRecordingClicked)="_onStopRecordingClicked()"
|
||||
(onDownloadRecordingClicked)="_onDownloadRecordingClicked($event)"
|
||||
(onDeleteRecordingClicked)="_onDeleteRecordingClicked($event)"
|
||||
(onPlayRecordingClicked)="_onPlayRecordingClicked($event)"
|
||||
></ov-recording-activity>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,23 +1,131 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { PanelType } from '../../../models/panel.model';
|
||||
import { OpenViduAngularConfigService } from '../../../services/config/openvidu-angular.config.service';
|
||||
import { PanelService } from '../../../services/panel/panel.service';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ov-activities-panel',
|
||||
templateUrl: './activities-panel.component.html',
|
||||
styleUrls: ['../panel.component.css','./activities-panel.component.css']
|
||||
styleUrls: ['../panel.component.css', './activities-panel.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ActivitiesPanelComponent implements OnInit {
|
||||
constructor(private panelService: PanelService) {}
|
||||
/**
|
||||
* Provides event notifications that fire when start recording button has been clicked.
|
||||
* The recording should be stated using the OpenVidu REST API.
|
||||
*/
|
||||
@Output() onStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
ngOnInit(): void {}
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button has been clicked.
|
||||
* The recording should be stopped using the OpenVidu REST API.
|
||||
*/
|
||||
@Output() onStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
ngOnDestroy() {}
|
||||
/**
|
||||
* Provides event notifications that fire when download recording button has been clicked.
|
||||
* The recording should be downloaded using the OpenVidu REST API.
|
||||
*/
|
||||
@Output() onDownloadRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
/**
|
||||
* Provides event notifications that fire when delete recording button has been clicked.
|
||||
* The recording should be deleted using the OpenVidu REST API.
|
||||
*/
|
||||
@Output() onDeleteRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
/**
|
||||
* Provides event notifications that fire when play recording button has been clicked.
|
||||
*/
|
||||
@Output() onPlayRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
expandedPanel: string = '';
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
showRecordingActivity: boolean = true;
|
||||
private panelSubscription: Subscription;
|
||||
private recordingActivitySub: Subscription;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(private panelService: PanelService, private libService: OpenViduAngularConfigService, private cd: ChangeDetectorRef) {}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.subscribeToPanelToggling();
|
||||
this.subscribeToActivitiesPanelDirective();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
if (this.panelSubscription) this.panelSubscription.unsubscribe();
|
||||
if (this.recordingActivitySub) this.recordingActivitySub.unsubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
close() {
|
||||
this.panelService.togglePanel(PanelType.ACTIVITIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onStartRecordingClicked() {
|
||||
this.onStartRecordingClicked.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onStopRecordingClicked() {
|
||||
this.onStopRecordingClicked.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onDownloadRecordingClicked(recordingId: string) {
|
||||
this.onDownloadRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onDeleteRecordingClicked(recordingId: string) {
|
||||
this.onDeleteRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onPlayRecordingClicked(recordingId: string) {
|
||||
this.onPlayRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
private subscribeToPanelToggling() {
|
||||
this.panelSubscription = this.panelService.panelOpenedObs.subscribe(
|
||||
(ev: { opened: boolean; type?: PanelType | string; expand?: string }) => {
|
||||
if (ev.type === PanelType.ACTIVITIES) {
|
||||
this.expandedPanel = ev.expand;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private subscribeToActivitiesPanelDirective() {
|
||||
this.recordingActivitySub = this.libService.recordingActivity.subscribe((value: boolean) => {
|
||||
this.showRecordingActivity = value;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,89 @@
|
|||
#recording-status {
|
||||
color: var(--ov-text-color);
|
||||
display: inline;
|
||||
padding: 3px;
|
||||
font-size: 11px;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
border-radius: var(--ov-panel-radius);
|
||||
}
|
||||
|
||||
.time-container {
|
||||
padding: 2px;
|
||||
}
|
||||
.recording-icon {
|
||||
font-size: 32px !important;
|
||||
height: 32px !important;
|
||||
width: 32px !important;
|
||||
}
|
||||
|
||||
.recording-duration {
|
||||
background-color: var(--ov-light-color);
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--ov-panel-radius);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.recording-duration mat-icon {
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
|
||||
.started {
|
||||
background-color: #005704;
|
||||
background-color: #3b7430 !important;
|
||||
color: var(--ov-text-color);
|
||||
}
|
||||
|
||||
.activity-icon.started, .failed {
|
||||
background-color: var(--ov-warn-color) !important;
|
||||
color: var(--ov-text-color);
|
||||
}
|
||||
.stopped {
|
||||
background-color: var(--ov-light-color);
|
||||
color: var(--ov-panel-text-color) !important;
|
||||
}
|
||||
|
||||
|
||||
#recording-file-item {
|
||||
padding: 0px 16px;
|
||||
.pending {
|
||||
background-color: #ffd79b !important;
|
||||
color: var(--ov-panel-text-color) !important;
|
||||
}
|
||||
|
||||
.recording-action-buttons{
|
||||
margin: auto;
|
||||
.panel-body-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.panel-body-container > .content {
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-flex: 1;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.recording-error {
|
||||
color: var(--ov-warn-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
.recording-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.recording-date {
|
||||
font-size: 12px !important;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.not-allowed-message {
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.recording-action-buttons {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#start-recording-btn {
|
||||
|
@ -32,6 +96,17 @@
|
|||
color: var(--ov-text-color);
|
||||
}
|
||||
|
||||
.delete-recording-btn {
|
||||
color: var(--ov-warn-color);
|
||||
}
|
||||
|
||||
mat-expansion-panel {
|
||||
margin: 0pc 0px 15px 0px;
|
||||
margin: 0px 0px 15px 0px;
|
||||
}
|
||||
|
||||
.blink {
|
||||
animation: blinker 1.5s linear infinite !important;
|
||||
}
|
||||
@keyframes blinker {
|
||||
50% { opacity: 0.4; }
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,89 +1,203 @@
|
|||
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { Component, OnInit, Output, EventEmitter, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { RecordingStatus } from '../../../../models/recording.model';
|
||||
import { RecordingService, RecordingInfo } from '../../../../services/recording/recording.service';
|
||||
import { OpenViduRole } from '../../../../models/participant.model';
|
||||
import { RecordingInfo, RecordingStatus } from '../../../../models/recording.model';
|
||||
import { ActionService } from '../../../../services/action/action.service';
|
||||
import { OpenViduAngularConfigService } from '../../../../services/config/openvidu-angular.config.service';
|
||||
import { ParticipantService } from '../../../../services/participant/participant.service';
|
||||
import { RecordingService } from '../../../../services/recording/recording.service';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ov-recording-activity',
|
||||
templateUrl: './recording-activity.component.html',
|
||||
styleUrls: ['./recording-activity.component.css', '../activities-panel.component.css']
|
||||
styleUrls: ['./recording-activity.component.css', '../activities-panel.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class RecordingActivityComponent implements OnInit {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Input() expanded: boolean;
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when start recording button has been clicked.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() startRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() onStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button has been clicked.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() stopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
||||
recStatusEnum = RecordingStatus;
|
||||
isSessionCreator = true;
|
||||
recording: RecordingInfo;
|
||||
recordingSubscription: Subscription;
|
||||
@Output() onStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when download recording button has been clicked.
|
||||
* The recording should be downloaded using the REST API.
|
||||
*/
|
||||
@Output() onDownloadRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when delete recording button has been clicked.
|
||||
* The recording should be deleted using the REST API.
|
||||
*/
|
||||
@Output() onDeleteRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when play recording button has been clicked.
|
||||
*/
|
||||
@Output() onPlayRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
opened: boolean = false;
|
||||
|
||||
constructor(private recordingService: RecordingService) {}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
recStatusEnum = RecordingStatus;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
isSessionCreator = false;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
liveRecording: RecordingInfo;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
recordingsList: RecordingInfo[] = [];
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
recordingError: any;
|
||||
|
||||
private recordingStatusSubscription: Subscription;
|
||||
private recordingListSubscription: Subscription;
|
||||
private recordingErrorSub: Subscription;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(
|
||||
private recordingService: RecordingService,
|
||||
private participantService: ParticipantService,
|
||||
private libService: OpenViduAngularConfigService,
|
||||
private actionService: ActionService,
|
||||
private cd: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.subscribeToRecordingStatus();
|
||||
this.subscribeToRecordingActivityDirective();
|
||||
this.isSessionCreator = this.participantService.getMyRole() === OpenViduRole.MODERATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
if (this.recordingSubscription) this.recordingSubscription.unsubscribe();
|
||||
if (this.recordingStatusSubscription) this.recordingStatusSubscription.unsubscribe();
|
||||
if (this.recordingListSubscription) this.recordingListSubscription.unsubscribe();
|
||||
if (this.recordingErrorSub) this.recordingErrorSub.unsubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
panelOpened() {
|
||||
//TODO EMITIR EVENTO
|
||||
//TODO emit event
|
||||
this.opened = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
panelClosed() {
|
||||
//TODO EMITIR EVENTO
|
||||
//TODO emit event
|
||||
this.opened = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
startRecording() {
|
||||
console.log('START RECORDING');
|
||||
this.startRecordingClicked.emit();
|
||||
//TODO: REMOVE
|
||||
const info: RecordingInfo = {
|
||||
status: RecordingStatus.STARTED,
|
||||
id: '1',
|
||||
name: 'akajo',
|
||||
reason: null
|
||||
};
|
||||
this.recordingService.startRecording(<any>info);
|
||||
}
|
||||
stopRecording() {
|
||||
console.log('STOP RECORDING');
|
||||
this.stopRecordingClicked.emit();
|
||||
//TODO: REMOVE
|
||||
const info: RecordingInfo = {
|
||||
status: RecordingStatus.STOPPED,
|
||||
id: '1',
|
||||
name: 'akajo',
|
||||
reason: 'lalal'
|
||||
};
|
||||
this.recordingService.stopRecording(<any>info);
|
||||
this.onStartRecordingClicked.emit();
|
||||
this.recordingService.updateStatus(RecordingStatus.STARTING);
|
||||
}
|
||||
|
||||
subscribeToRecordingStatus() {
|
||||
this.recordingSubscription = this.recordingService.recordingStatusObs.subscribe((info: RecordingInfo) => {
|
||||
if (info) {
|
||||
this.recordingStatus = info.status;
|
||||
if (info.status === RecordingStatus.STARTED) {
|
||||
this.recording = info;
|
||||
} else {
|
||||
this.recording = null;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
stopRecording() {
|
||||
this.onStopRecordingClicked.emit();
|
||||
this.recordingService.updateStatus(RecordingStatus.STOPPING);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
deleteRecording(id: string) {
|
||||
const succsessCallback = () => {
|
||||
this.onDeleteRecordingClicked.emit(id);
|
||||
};
|
||||
this.actionService.openDeleteRecordingDialog(succsessCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
download(recordingId: string) {
|
||||
this.onDownloadRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
play(recordingId: string) {
|
||||
this.onPlayRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
private subscribeToRecordingStatus() {
|
||||
this.recordingStatusSubscription = this.recordingService.recordingStatusObs.subscribe(
|
||||
(ev: { info: RecordingInfo; time?: Date }) => {
|
||||
if (ev?.info) {
|
||||
this.recordingStatus = ev.info.status;
|
||||
if (ev.info.status === RecordingStatus.STARTED) {
|
||||
this.liveRecording = ev.info;
|
||||
} else {
|
||||
this.liveRecording = null;
|
||||
}
|
||||
}
|
||||
this.cd.markForCheck();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private subscribeToRecordingActivityDirective() {
|
||||
this.recordingListSubscription = this.libService.recordingsListObs.subscribe((recordingList: RecordingInfo[]) => {
|
||||
this.recordingsList = recordingList;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
|
||||
this.recordingErrorSub = this.libService.recordingErrorObs.subscribe((error: any) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.recordingService.updateStatus(RecordingStatus.FAILED);
|
||||
this.recordingError = error.error?.message || error.message || error;
|
||||
console.log('REC ERROR', this.recordingError)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,6 +20,12 @@ export class BackgroundEffectsPanelComponent implements OnInit {
|
|||
private backgrounds: BackgroundEffect[];
|
||||
private backgroundSubs: Subscription;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param panelService
|
||||
* @param backgroundService
|
||||
* @param cd
|
||||
*/
|
||||
constructor(private panelService: PanelService, private backgroundService: VirtualBackgroundService, private cd: ChangeDetectorRef) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
|
|
|
@ -176,11 +176,13 @@ export class SessionComponent implements OnInit {
|
|||
this.updateLayoutInterval = setInterval(() => this.layoutService.update(), 50);
|
||||
});
|
||||
|
||||
this.menuSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: PanelType }) => {
|
||||
if (this.sideMenu) {
|
||||
ev.opened ? this.sideMenu.open() : this.sideMenu.close();
|
||||
}
|
||||
});
|
||||
this.menuSubscription = this.panelService.panelOpenedObs
|
||||
.pipe(skip(1))
|
||||
.subscribe((ev: { opened: boolean; type?: PanelType | string }) => {
|
||||
if (this.sideMenu) {
|
||||
ev.opened ? this.sideMenu.open() : this.sideMenu.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected subscribeToLayoutWidth() {
|
||||
|
|
|
@ -113,16 +113,4 @@
|
|||
|
||||
input {
|
||||
caret-color: #ffffff !important;
|
||||
}
|
||||
|
||||
.poster_img {
|
||||
position: absolute;
|
||||
z-index: 888;
|
||||
max-width: 70%;
|
||||
max-height: 70%;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
margin: auto;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
|
@ -70,8 +70,8 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
#recording-tag {
|
||||
padding: 0 15px;
|
||||
.recording-tag {
|
||||
padding: 0 10px;
|
||||
background-color: var(--ov-warn-color);
|
||||
border-radius: var(--ov-panel-radius);
|
||||
width: fit-content;
|
||||
|
@ -79,17 +79,18 @@
|
|||
text-align: center;
|
||||
line-height: 20px;
|
||||
margin: auto;
|
||||
animation: blinker 1.5s linear infinite;
|
||||
|
||||
|
||||
}
|
||||
#recording-tag mat-icon {
|
||||
.recording-tag mat-icon {
|
||||
font-size: 16px;
|
||||
display: inline;
|
||||
vertical-align: sub;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.blink {
|
||||
animation: blinker 1.5s linear infinite;
|
||||
}
|
||||
|
||||
#point {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
|
@ -140,5 +141,5 @@
|
|||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% { opacity: 0.2; }
|
||||
}
|
||||
50% { opacity: 0.3; }
|
||||
}
|
|
@ -2,11 +2,12 @@
|
|||
<div fxFlex="20%" fxLayoutAlign="start center" id="info-container">
|
||||
<div>
|
||||
<img *ngIf="!isMinimal && showLogo" id="branding-logo" src="assets/images/logo.png" ovLogo />
|
||||
<div id="session-info-container" [class.colapsed]="isRecording">
|
||||
<div id="session-info-container" [class.colapsed]="recordingStatus === _recordingStatus.STARTED">
|
||||
<span id="session-name" *ngIf="!isMinimal && session && session.sessionId && showSessionName">{{ session.sessionId }}</span>
|
||||
<div id="recording-tag" *ngIf="isRecording">
|
||||
<mat-icon>radio_button_checked</mat-icon>
|
||||
<span>REC</span>
|
||||
<div *ngIf="recordingStatus === _recordingStatus.STARTED" id="recording-tag" class="recording-tag">
|
||||
<mat-icon class="blink">radio_button_checked</mat-icon>
|
||||
<span class="blink">REC</span>
|
||||
<span> | {{ recordingTime | date: 'H:mm:ss' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,7 +34,9 @@
|
|||
[class.warn-btn]="!isWebcamVideoActive"
|
||||
>
|
||||
<mat-icon *ngIf="isWebcamVideoActive" matTooltip="{{ 'TOOLBAR.MUTE_VIDEO' | translate }}" id="videocam">videocam</mat-icon>
|
||||
<mat-icon *ngIf="!isWebcamVideoActive" matTooltip="{{ 'TOOLBAR.UNMUTE_VIDEO' | translate }}" id="videocam_off">videocam_off</mat-icon>
|
||||
<mat-icon *ngIf="!isWebcamVideoActive" matTooltip="{{ 'TOOLBAR.UNMUTE_VIDEO' | translate }}" id="videocam_off"
|
||||
>videocam_off</mat-icon
|
||||
>
|
||||
</button>
|
||||
|
||||
<!-- Screenshare button -->
|
||||
|
@ -49,31 +52,19 @@
|
|||
<mat-icon *ngIf="isScreenShareActive" matTooltip="{{ 'TOOLBAR.DISABLE_SCREEN' | translate }}">screen_share</mat-icon>
|
||||
</button>
|
||||
|
||||
<!-- Fullscreen button -->
|
||||
<button
|
||||
mat-icon-button
|
||||
id="fullscreen-btn"
|
||||
*ngIf="!isMinimal && showFullscreenButton && !showBackgroundEffectsButton"
|
||||
(click)="toggleFullscreen()"
|
||||
[disabled]="isConnectionLost"
|
||||
[class.active-btn]="isFullscreenActive"
|
||||
>
|
||||
<mat-icon *ngIf="isFullscreenActive" matTooltip="{{ 'TOOLBAR.EXIT_FULLSCREEN' | translate }}">fullscreen_exit</mat-icon>
|
||||
<mat-icon *ngIf="!isFullscreenActive" matTooltip="{{ 'TOOLBAR.FULLSCREEN' | translate }}">fullscreen</mat-icon>
|
||||
</button>
|
||||
|
||||
<!-- More options button -->
|
||||
<button
|
||||
mat-icon-button
|
||||
id="more-options-btn"
|
||||
*ngIf="!isMinimal && showBackgroundEffectsButton"
|
||||
*ngIf="!isMinimal && showMoreOptionsButton"
|
||||
[matMenuTriggerFor]="menu"
|
||||
[disabled]="isConnectionLost"
|
||||
>
|
||||
<mat-icon matTooltip="{{ 'TOOLBAR.MORE_OPTIONS' | translate }}">more_vert</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<mat-menu #menu="matMenu" id="more-options-menu">
|
||||
<!-- Fullscreen button -->
|
||||
<button mat-menu-item id="fullscreen-btn" (click)="toggleFullscreen()">
|
||||
<button *ngIf="showFullscreenButton" mat-menu-item id="fullscreen-btn" (click)="toggleFullscreen()">
|
||||
<mat-icon *ngIf="!isFullscreenActive">fullscreen</mat-icon>
|
||||
<span *ngIf="!isFullscreenActive">{{ 'TOOLBAR.FULLSCREEN' | translate }}</span>
|
||||
|
||||
|
@ -82,15 +73,23 @@
|
|||
</button>
|
||||
|
||||
<!-- Recording button -->
|
||||
<!-- <button
|
||||
*ngIf="!isMinimal && showActivitiesPanelButton"
|
||||
<button
|
||||
*ngIf="!isMinimal && showRecordingButton"
|
||||
mat-menu-item
|
||||
id="recording-btn"
|
||||
(click)="toggleActivitiesPanel('recording')"
|
||||
[disabled]="
|
||||
recordingStatus === _recordingStatus.STARTING || recordingStatus === _recordingStatus.STOPPING || !isSessionCreator
|
||||
"
|
||||
(click)="toggleRecording()"
|
||||
>
|
||||
<mat-icon color="warn">radio_button_checked</mat-icon>
|
||||
<span>Recording</span>
|
||||
</button> -->
|
||||
<span *ngIf="recordingStatus === _recordingStatus.STOPPED || recordingStatus === _recordingStatus.STOPPING">
|
||||
{{ 'TOOLBAR.START_RECORDING' | translate }}
|
||||
</span>
|
||||
<span *ngIf="recordingStatus === _recordingStatus.STARTED || recordingStatus === _recordingStatus.STARTING">
|
||||
{{ 'TOOLBAR.STOP_RECORDING' | translate }}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<!-- Virtual background button -->
|
||||
<button
|
||||
|
@ -117,17 +116,17 @@
|
|||
</div>
|
||||
<div fxFlex="20%" fxFlexOrder="3" fxLayoutAlign="end center" id="menu-buttons-container">
|
||||
<!-- Default activities button -->
|
||||
<!-- <button
|
||||
<button
|
||||
mat-icon-button
|
||||
id="activities-panel-btn"
|
||||
*ngIf="!isMinimal && showActivitiesPanelButton"
|
||||
matTooltip="Activities"
|
||||
matTooltip="{{ 'TOOLBAR.ACTIVITIES' | translate }}"
|
||||
(click)="toggleActivitiesPanel()"
|
||||
[disabled]="isConnectionLost"
|
||||
[class.active-btn]="isActivitiesOpened"
|
||||
>
|
||||
<mat-icon>category</mat-icon>
|
||||
</button> -->
|
||||
</button>
|
||||
|
||||
<!-- Default participants button -->
|
||||
<button
|
||||
|
|
|
@ -31,11 +31,11 @@ import {
|
|||
ToolbarAdditionalButtonsDirective,
|
||||
ToolbarAdditionalPanelButtonsDirective
|
||||
} from '../../directives/template/openvidu-angular.directive';
|
||||
import { ParticipantAbstractModel } from '../../models/participant.model';
|
||||
import { OpenViduRole, ParticipantAbstractModel } from '../../models/participant.model';
|
||||
import { PlatformService } from '../../services/platform/platform.service';
|
||||
import { MatMenuTrigger } from '@angular/material/menu';
|
||||
import { RecordingInfo, RecordingService } from '../../services/recording/recording.service';
|
||||
import { RecordingStatus } from '../../models/recording.model';
|
||||
import { RecordingService } from '../../services/recording/recording.service';
|
||||
import { RecordingInfo, RecordingStatus } from '../../models/recording.model';
|
||||
import { TranslateService } from '../../services/translate/translate.service';
|
||||
|
||||
/**
|
||||
|
@ -165,17 +165,24 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
*/
|
||||
@Output() onParticipantsPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* TODO: WIP
|
||||
* Provides event notifications that fire when background effects button has been clicked.
|
||||
*/
|
||||
// @Output() onBackgroundEffectsButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when chat panel button has been clicked.
|
||||
*/
|
||||
@Output() onChatPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when activities panel button has been clicked.
|
||||
*/
|
||||
@Output() onActivitiesPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||
/**
|
||||
* Provides event notifications that fire when start recording button has been clicked.
|
||||
*/
|
||||
@Output() onStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button has been clicked.
|
||||
*/
|
||||
@Output() onStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -257,6 +264,17 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
* @ignore
|
||||
*/
|
||||
showLeaveButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
showRecordingButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
showMoreOptionsButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -286,7 +304,21 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
/**
|
||||
* @ignore
|
||||
*/
|
||||
isRecording: boolean = false;
|
||||
recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
_recordingStatus = RecordingStatus;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
recordingTime: Date;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
isSessionCreator: boolean = false;
|
||||
|
||||
private log: ILogger;
|
||||
private minimalSub: Subscription;
|
||||
|
@ -297,8 +329,8 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
private fullscreenButtonSub: Subscription;
|
||||
private backgroundEffectsButtonSub: Subscription;
|
||||
private leaveButtonSub: Subscription;
|
||||
private recordingButtonSub: Subscription;
|
||||
private recordingSubscription: Subscription;
|
||||
|
||||
private activitiesPanelButtonSub: Subscription;
|
||||
private participantsPanelButtonSub: Subscription;
|
||||
private chatPanelButtonSub: Subscription;
|
||||
|
@ -375,6 +407,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
if (this.fullscreenButtonSub) this.fullscreenButtonSub.unsubscribe();
|
||||
if (this.backgroundEffectsButtonSub) this.backgroundEffectsButtonSub.unsubscribe();
|
||||
if (this.leaveButtonSub) this.leaveButtonSub.unsubscribe();
|
||||
if (this.recordingButtonSub) this.recordingButtonSub.unsubscribe();
|
||||
if (this.participantsPanelButtonSub) this.participantsPanelButtonSub.unsubscribe();
|
||||
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
|
||||
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
|
||||
|
@ -393,7 +426,10 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
await this.openviduService.publishAudio(!this.isAudioActive);
|
||||
} catch (error) {
|
||||
this.log.e('There was an error toggling microphone:', error.code, error.message);
|
||||
this.actionService.openDialog(this.translateService.translate('ERRORS.TOGGLE_MICROPHONE'), error?.error || error?.message || error);
|
||||
this.actionService.openDialog(
|
||||
this.translateService.translate('ERRORS.TOGGLE_MICROPHONE'),
|
||||
error?.error || error?.message || error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -427,7 +463,10 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
} catch (error) {
|
||||
this.log.e('There was an error toggling screen share', error.code, error.message);
|
||||
if (error && error.name === 'SCREEN_SHARING_NOT_SUPPORTED') {
|
||||
this.actionService.openDialog(this.translateService.translate('ERRORS.SCREEN_SHARING'), this.translateService.translate('ERRORS.SCREEN_SUPPORT'));
|
||||
this.actionService.openDialog(
|
||||
this.translateService.translate('ERRORS.SCREEN_SHARING'),
|
||||
this.translateService.translate('ERRORS.SCREEN_SUPPORT')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -442,19 +481,27 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO: WIP
|
||||
* @ignore
|
||||
*/
|
||||
toggleActivitiesPanel(expandPanel: string) {
|
||||
// this.onActivitiesPanelButtonClicked.emit();
|
||||
// this.panelService.togglePanel(PanelType.ACTIVITIES);
|
||||
toggleRecording() {
|
||||
if (this.recordingStatus === RecordingStatus.STARTED) {
|
||||
this.log.d('Stopping recording');
|
||||
this.onStopRecordingClicked.emit();
|
||||
this.recordingService.updateStatus(RecordingStatus.STOPPING);
|
||||
} else if (this.recordingStatus === RecordingStatus.STOPPED) {
|
||||
this.onStartRecordingClicked.emit();
|
||||
this.recordingService.updateStatus(RecordingStatus.STARTING);
|
||||
|
||||
if (this.showActivitiesPanelButton && !this.isActivitiesOpened) {
|
||||
this.toggleActivitiesPanel('recording');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
toggleBackgroundEffects() {
|
||||
// this.onBackgroundEffectsButtonClicked.emit();
|
||||
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
|
||||
}
|
||||
|
||||
|
@ -483,6 +530,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
this.onFullscreenButtonClicked.emit();
|
||||
}
|
||||
|
||||
private toggleActivitiesPanel(expandPanel: string) {
|
||||
this.onActivitiesPanelButtonClicked.emit();
|
||||
this.panelService.togglePanel(PanelType.ACTIVITIES, expandPanel);
|
||||
}
|
||||
|
||||
protected subscribeToReconnection() {
|
||||
this.session.on('reconnecting', () => {
|
||||
if (this.panelService.isPanelOpened()) {
|
||||
|
@ -495,14 +547,17 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
protected subscribeToMenuToggling() {
|
||||
this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: PanelType }) => {
|
||||
this.isChatOpened = ev.opened && ev.type === PanelType.CHAT;
|
||||
this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
||||
this.isActivitiesOpened = ev.opened && ev.type === PanelType.ACTIVITIES;
|
||||
if (this.isChatOpened) {
|
||||
this.unreadMessages = 0;
|
||||
this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe(
|
||||
(ev: { opened: boolean; type?: PanelType | string }) => {
|
||||
this.isChatOpened = ev.opened && ev.type === PanelType.CHAT;
|
||||
this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
||||
this.isActivitiesOpened = ev.opened && ev.type === PanelType.ACTIVITIES;
|
||||
if (this.isChatOpened) {
|
||||
this.unreadMessages = 0;
|
||||
}
|
||||
this.cd.markForCheck();
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
protected subscribeToChatMessages() {
|
||||
|
@ -520,17 +575,20 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
this.isWebcamVideoActive = p.isCameraVideoActive();
|
||||
this.isAudioActive = p.isCameraAudioActive() || p.isScreenAudioActive();
|
||||
this.isScreenShareActive = p.isScreenActive();
|
||||
this.isSessionCreator = p.getRole() === OpenViduRole.MODERATOR;
|
||||
this.cd.markForCheck();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private subscribeToRecordingStatus() {
|
||||
//TODO: WIP
|
||||
// this.recordingSubscription = this.recordingService.recordingStatusObs.pipe(skip(1)).subscribe((info: RecordingInfo) => {
|
||||
// this.isRecording = info.status === RecordingStatus.STARTED;
|
||||
// this.cd.markForCheck();
|
||||
// });
|
||||
this.recordingSubscription = this.recordingService.recordingStatusObs
|
||||
.pipe(skip(1))
|
||||
.subscribe((ev: { info: RecordingInfo; time?: Date }) => {
|
||||
this.recordingStatus = ev.info.status;
|
||||
this.recordingTime = ev.time;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
private subscribeToToolbarDirectives() {
|
||||
|
@ -544,12 +602,19 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
this.fullscreenButtonSub = this.libService.fullscreenButtonObs.subscribe((value: boolean) => {
|
||||
this.showFullscreenButton = value;
|
||||
this.checkDisplayMoreOptions();
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
this.leaveButtonSub = this.libService.leaveButtonObs.subscribe((value: boolean) => {
|
||||
this.showLeaveButton = value;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
|
||||
this.recordingButtonSub = this.libService.recordingButton.subscribe((value: boolean) => {
|
||||
this.showRecordingButton = value;
|
||||
this.checkDisplayMoreOptions();
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
this.chatPanelButtonSub = this.libService.chatPanelButtonObs.subscribe((value: boolean) => {
|
||||
this.showChatPanelButton = value;
|
||||
this.cd.markForCheck();
|
||||
|
@ -558,12 +623,13 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
this.showParticipantsPanelButton = value;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
// this.activitiesPanelButtonSub = this.libService.activitiesPanelButtonObs.subscribe((value: boolean) => {
|
||||
// this.showActivitiesPanelButton = value;
|
||||
// this.cd.markForCheck();
|
||||
// });
|
||||
this.activitiesPanelButtonSub = this.libService.activitiesPanelButtonObs.subscribe((value: boolean) => {
|
||||
this.showActivitiesPanelButton = value;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
this.backgroundEffectsButtonSub = this.libService.backgroundEffectsButton.subscribe((value: boolean) => {
|
||||
this.showBackgroundEffectsButton = value;
|
||||
this.checkDisplayMoreOptions();
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
this.displayLogoSub = this.libService.displayLogoObs.subscribe((value: boolean) => {
|
||||
|
@ -575,4 +641,8 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
private checkDisplayMoreOptions() {
|
||||
this.showMoreOptionsButton = this.showFullscreenButton || this.showBackgroundEffectsButton || this.showRecordingButton;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,5 @@
|
|||
margin: auto;
|
||||
text-align: -webkit-center;
|
||||
text-align: -moz-center;
|
||||
color: var(--ov-text-color);
|
||||
color: var(--ov-panel-text-color);
|
||||
}
|
|
@ -1,20 +1,20 @@
|
|||
<div id="call-container">
|
||||
<div id="pre-join-container" *ngIf="showPrejoin && tokensReceived && participantReady && !joinSessionClicked">
|
||||
|
||||
<div id="pre-join-container" *ngIf="showPrejoin && tokensReceived && participantReady">
|
||||
<ov-pre-join (onJoinButtonClicked)="_onJoinButtonClicked()"></ov-pre-join>
|
||||
<!-- <ov-user-settings (onJoinClicked)="_onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings> -->
|
||||
</div>
|
||||
|
||||
<div id="spinner" *ngIf="(joinSessionClicked || !showPrejoin) && !participantReady && !error">
|
||||
<div id="spinner" *ngIf="!participantReady && !streamPlaying && !error">
|
||||
<mat-spinner [diameter]="50"></mat-spinner>
|
||||
<span>{{ 'PREJOIN.PREPARING' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div id="spinner" *ngIf="joinSessionClicked && !participantReady && error">
|
||||
<div id="spinner" *ngIf="!participantReady && error">
|
||||
<mat-icon class="error-icon">error</mat-icon>
|
||||
<span>{{ errorMessage }}</span>
|
||||
</div>
|
||||
|
||||
<div id="session-container" *ngIf="(joinSessionClicked || !showPrejoin) && participantReady && tokensReceived && !error">
|
||||
<div id="session-container" *ngIf="showVideoconference || (!showPrejoin && participantReady && tokensReceived && !error)">
|
||||
<ov-session (onSessionCreated)="_onSessionCreated($event)">
|
||||
<ng-template #toolbar>
|
||||
<ng-container *ngIf="openviduAngularToolbarTemplate">
|
||||
|
@ -47,6 +47,9 @@
|
|||
(onFullscreenButtonClicked)="onFullscreenButtonClicked()"
|
||||
(onParticipantsPanelButtonClicked)="onParticipantsPanelButtonClicked()"
|
||||
(onChatPanelButtonClicked)="onChatPanelButtonClicked()"
|
||||
(onActivitiesPanelButtonClicked)="onActivitiesPanelButtonClicked()"
|
||||
(onStartRecordingClicked)="onStartRecordingClicked('toolbar')"
|
||||
(onStopRecordingClicked)="onStopRecordingClicked('toolbar')"
|
||||
>
|
||||
<ng-template #toolbarAdditionalButtons>
|
||||
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container>
|
||||
|
@ -87,11 +90,14 @@
|
|||
</ng-template>
|
||||
|
||||
<ng-template #defaultActivitiesPanel>
|
||||
<!-- <ov-activities-panel
|
||||
<ov-activities-panel
|
||||
id="default-activities-panel"
|
||||
(onStartRecordingClicked)="onStartRecordingClicked()"
|
||||
(onStopRecordingClicked)="onStopRecordingClicked()"
|
||||
></ov-activities-panel> -->
|
||||
(onStartRecordingClicked)="onStartRecordingClicked('panel')"
|
||||
(onStopRecordingClicked)="onStopRecordingClicked('panel')"
|
||||
(onDownloadRecordingClicked)="onDownloadRecordingClicked($event)"
|
||||
(onDeleteRecordingClicked)="onDeleteRecordingClicked($event)"
|
||||
(onPlayRecordingClicked)="onPlayRecordingClicked($event)"
|
||||
></ov-activities-panel>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #defaultParticipantsPanel>
|
||||
|
|
|
@ -27,13 +27,14 @@ import {
|
|||
ActivitiesPanelDirective
|
||||
} from '../../directives/template/openvidu-angular.directive';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { OpenViduEdition } from '../../models/openvidu.model';
|
||||
import { ParticipantAbstractModel, 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';
|
||||
import { LoggerService } from '../../services/logger/logger.service';
|
||||
import { OpenViduEdition, OpenViduService } from '../../services/openvidu/openvidu.service';
|
||||
import { OpenViduService } from '../../services/openvidu/openvidu.service';
|
||||
import { ParticipantService } from '../../services/participant/participant.service';
|
||||
import { StorageService } from '../../services/storage/storage.service';
|
||||
import { TokenService } from '../../services/token/token.service';
|
||||
|
@ -70,6 +71,7 @@ import { TranslateService } from '../../services/translate/translate.service';
|
|||
* | **streamDisplayAudioDetection** | `boolean` | {@link StreamDisplayAudioDetectionDirective} |
|
||||
* | **streamSettingsButton** | `boolean` | {@link StreamSettingsButtonDirective} |
|
||||
* | **participantPanelItemMuteButton** | `boolean` | {@link ParticipantPanelItemMuteButtonDirective} |
|
||||
* | **recordingActivityRecordingList** | `{@link RecordingInfo}[]` | {@link RecordingActivityRecordingListDirective} |
|
||||
*
|
||||
* <p class="component-link-text">
|
||||
* <span class="italic">See all {@link ApiDirectiveModule API Directives}</span>
|
||||
|
@ -325,6 +327,50 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
*/
|
||||
@Output() onToolbarChatPanelButtonClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when activities panel button has been clicked.
|
||||
*/
|
||||
@Output() onToolbarActivitiesPanelButtonClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when start recording button is clicked {@link ToolbarComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onToolbarStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button is clicked from {@link ToolbarComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onToolbarStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when start recording button is clicked {@link ActivitiesPanelComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when download recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
* The recording should be downloaded using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelDownloadRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when delete recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
* The recording should be deleted using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelDeleteRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when play recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
*/
|
||||
@Output() onActivitiesPanelPlayRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when OpenVidu Session is created.
|
||||
* See {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Session.html openvidu-browser Session}.
|
||||
|
@ -339,7 +385,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
joinSessionClicked: boolean = false;
|
||||
showVideoconference: boolean = false;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -360,6 +406,8 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
* @internal
|
||||
*/
|
||||
showPrejoin: boolean = true;
|
||||
|
||||
streamPlaying = false;
|
||||
private externalParticipantName: string;
|
||||
private prejoinSub: Subscription;
|
||||
private participantNameSub: Subscription;
|
||||
|
@ -404,12 +452,9 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
try {
|
||||
const publisher = await this.openviduService.initDefaultPublisher(undefined);
|
||||
if (publisher) {
|
||||
publisher.once('accessDenied', (e: any) => {
|
||||
this.handlePublisherError(e);
|
||||
});
|
||||
publisher.once('accessAllowed', () => {
|
||||
this.participantReady = true;
|
||||
});
|
||||
publisher.once('accessDenied', (e: any) => this.handlePublisherError(e));
|
||||
publisher.once('accessAllowed', () => (this.participantReady = true));
|
||||
publisher.once('streamPlaying', () => (this.streamPlaying = true));
|
||||
}
|
||||
} catch (error) {
|
||||
this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true);
|
||||
|
@ -477,14 +522,13 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
this.openviduAngularChatPanelTemplate = this.defaultChatPanelTemplate;
|
||||
}
|
||||
|
||||
// TODO: WIP
|
||||
// if (this.externalActivitiesPanel) {
|
||||
// this.log.d('Setting EXTERNAL ACTIVITIES PANEL');
|
||||
// this.openviduAngularActivitiesPanelTemplate = this.externalActivitiesPanel.template;
|
||||
// } else {
|
||||
// this.log.d('Setting DEFAULT ACTIVITIES PANEL');
|
||||
// this.openviduAngularActivitiesPanelTemplate = this.defaultActivitiesPanelTemplate;
|
||||
// }
|
||||
if (this.externalActivitiesPanel) {
|
||||
this.log.d('Setting EXTERNAL ACTIVITIES PANEL');
|
||||
this.openviduAngularActivitiesPanelTemplate = this.externalActivitiesPanel.template;
|
||||
} else {
|
||||
this.log.d('Setting DEFAULT ACTIVITIES PANEL');
|
||||
this.openviduAngularActivitiesPanelTemplate = this.defaultActivitiesPanelTemplate;
|
||||
}
|
||||
|
||||
if (this.externalAdditionalPanels) {
|
||||
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
|
||||
|
@ -514,14 +558,15 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
* @internal
|
||||
*/
|
||||
_onJoinButtonClicked() {
|
||||
this.joinSessionClicked = true;
|
||||
this.showVideoconference = true;
|
||||
this.showPrejoin = false;
|
||||
this.onJoinButtonClicked.emit();
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onLeaveButtonClicked() {
|
||||
this.joinSessionClicked = false;
|
||||
this.showVideoconference = false;
|
||||
this.participantReady = false;
|
||||
this.onToolbarLeaveButtonClicked.emit();
|
||||
}
|
||||
|
@ -561,6 +606,56 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
onChatPanelButtonClicked() {
|
||||
this.onToolbarChatPanelButtonClicked.emit();
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onActivitiesPanelButtonClicked() {
|
||||
this.onToolbarActivitiesPanelButtonClicked.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onStartRecordingClicked(from: string) {
|
||||
if (from === 'toolbar') {
|
||||
this.onToolbarStartRecordingClicked.emit();
|
||||
} else if (from === 'panel') {
|
||||
this.onActivitiesPanelStartRecordingClicked.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onStopRecordingClicked(from: string) {
|
||||
if (from === 'toolbar') {
|
||||
this.onToolbarStopRecordingClicked.emit();
|
||||
} else if (from === 'panel') {
|
||||
this.onActivitiesPanelStopRecordingClicked.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onDownloadRecordingClicked(recordingId: string) {
|
||||
this.onActivitiesPanelDownloadRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onDeleteRecordingClicked(recordingId: string) {
|
||||
this.onActivitiesPanelDeleteRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onPlayRecordingClicked(recordingId: string) {
|
||||
this.onActivitiesPanelPlayRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import { Directive, AfterViewInit, OnDestroy, Input, ElementRef } from '@angular/core';
|
||||
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
||||
|
||||
/**
|
||||
* The **recordingActivity** directive allows show/hide the recording activity in {@link ActivitiesPanelComponent} activity panel component.
|
||||
*
|
||||
* Default: `true`
|
||||
*
|
||||
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `activitiesPanel` component:
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [activitiesPanelRecordingActivity]="false"></ov-videoconference>
|
||||
*
|
||||
* \
|
||||
* And it also can be used in the {@link ActivitiesPanelComponent}.
|
||||
* @example
|
||||
* <ov-activities-panel [recordingActivity]="false"></ov-activities-panel>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[activitiesPanelRecordingActivity], ov-activities-panel[recordingActivity]'
|
||||
})
|
||||
export class ActivitiesPanelRecordingActivityDirective implements AfterViewInit, OnDestroy {
|
||||
@Input() set activitiesPanelRecordingActivity(value: boolean) {
|
||||
this.recordingActivityValue = value;
|
||||
this.update(this.recordingActivityValue);
|
||||
}
|
||||
@Input() set recordingList(value: boolean) {
|
||||
this.recordingActivityValue = value;
|
||||
this.update(this.recordingActivityValue);
|
||||
}
|
||||
|
||||
recordingActivityValue: boolean = true;
|
||||
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.update(this.recordingActivityValue);
|
||||
}
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
clear() {
|
||||
this.recordingActivityValue = true;
|
||||
this.update(true);
|
||||
}
|
||||
|
||||
update(value: boolean) {
|
||||
if (this.libService.recordingActivity.getValue() !== value) {
|
||||
this.libService.recordingActivity.next(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { ActivitiesPanelRecordingActivityDirective } from './activities-panel.directive';
|
||||
import { LogoDirective } from './internals.directive';
|
||||
import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive';
|
||||
import { RecordingActivityRecordingErrorDirective, RecordingActivityRecordingsListDirective } from './recording-activity.directive';
|
||||
import {
|
||||
StreamDisplayParticipantNameDirective,
|
||||
StreamDisplayAudioDetectionDirective,
|
||||
|
@ -15,7 +17,8 @@ import {
|
|||
ToolbarDisplaySessionNameDirective,
|
||||
ToolbarDisplayLogoDirective,
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
ToolbarBackgroundEffectsButtonDirective
|
||||
ToolbarBackgroundEffectsButtonDirective,
|
||||
ToolbarRecordingButtonDirective
|
||||
} from './toolbar.directive';
|
||||
import {
|
||||
AudioMutedDirective,
|
||||
|
@ -38,6 +41,7 @@ import {
|
|||
ToolbarFullscreenButtonDirective,
|
||||
ToolbarBackgroundEffectsButtonDirective,
|
||||
ToolbarLeaveButtonDirective,
|
||||
ToolbarRecordingButtonDirective,
|
||||
ToolbarParticipantsPanelButtonDirective,
|
||||
ToolbarChatPanelButtonDirective,
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
|
@ -48,7 +52,10 @@ import {
|
|||
StreamSettingsButtonDirective,
|
||||
LogoDirective,
|
||||
ParticipantPanelItemMuteButtonDirective,
|
||||
ParticipantNameDirective
|
||||
ParticipantNameDirective,
|
||||
ActivitiesPanelRecordingActivityDirective,
|
||||
RecordingActivityRecordingsListDirective,
|
||||
RecordingActivityRecordingErrorDirective
|
||||
],
|
||||
exports: [
|
||||
MinimalDirective,
|
||||
|
@ -60,6 +67,7 @@ import {
|
|||
ToolbarFullscreenButtonDirective,
|
||||
ToolbarBackgroundEffectsButtonDirective,
|
||||
ToolbarLeaveButtonDirective,
|
||||
ToolbarRecordingButtonDirective,
|
||||
ToolbarParticipantsPanelButtonDirective,
|
||||
ToolbarChatPanelButtonDirective,
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
|
@ -70,7 +78,10 @@ import {
|
|||
StreamSettingsButtonDirective,
|
||||
LogoDirective,
|
||||
ParticipantPanelItemMuteButtonDirective,
|
||||
ParticipantNameDirective
|
||||
ParticipantNameDirective,
|
||||
ActivitiesPanelRecordingActivityDirective,
|
||||
RecordingActivityRecordingsListDirective,
|
||||
RecordingActivityRecordingErrorDirective
|
||||
]
|
||||
})
|
||||
export class ApiDirectiveModule {}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import { Directive, AfterViewInit, OnDestroy, Input, ElementRef } from '@angular/core';
|
||||
import { RecordingInfo } from '../../models/recording.model';
|
||||
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
||||
|
||||
/**
|
||||
* The **recordingsList** directive allows show the recordings available for the session in {@link RecordingActivityComponent}.
|
||||
*
|
||||
* Default: `[]`
|
||||
*
|
||||
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `recordingActivity` component:
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [recordingActivityRecordingsList]="list"></ov-videoconference>
|
||||
*
|
||||
* \
|
||||
* And it also can be used in the {@link RecordingActivityComponent}.
|
||||
* @example
|
||||
* <ov-recording-activity [recordingsList]="list"></ov-recording-activity>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[recordingActivityRecordingsList], ov-recording-activity[recordingsList]'
|
||||
})
|
||||
export class RecordingActivityRecordingsListDirective implements AfterViewInit, OnDestroy {
|
||||
@Input() set recordingActivityRecordingsList(value: RecordingInfo[]) {
|
||||
this.recordingsValue = value;
|
||||
this.update(this.recordingsValue);
|
||||
}
|
||||
@Input() set recordingsList(value: RecordingInfo[]) {
|
||||
this.recordingsValue = value;
|
||||
this.update(this.recordingsValue);
|
||||
}
|
||||
|
||||
recordingsValue: RecordingInfo [] = [];
|
||||
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.update(this.recordingsValue);
|
||||
}
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
clear() {
|
||||
this.recordingsValue = null;
|
||||
this.update(null);
|
||||
}
|
||||
|
||||
update(value: RecordingInfo[]) {
|
||||
if (this.libService.recordingsList.getValue() !== value) {
|
||||
this.libService.recordingsList.next(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **recordingError** directive allows to show any possible error with the recording in the {@link RecordingActivityComponent}.
|
||||
*
|
||||
* Default: `[]`
|
||||
*
|
||||
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `recordingActivity` component:
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [recordingActivityRecordingError]="error"></ov-videoconference>
|
||||
*
|
||||
* \
|
||||
* And it also can be used in the {@link RecordingActivityComponent}.
|
||||
* @example
|
||||
* <ov-recording-activity [recordingError]="error"></ov-recording-activity>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[recordingActivityRecordingError], ov-recording-activity[recordingError]'
|
||||
})
|
||||
export class RecordingActivityRecordingErrorDirective implements AfterViewInit, OnDestroy {
|
||||
@Input() set recordingActivityRecordingError(value: any) {
|
||||
this.recordingErrorValue = value;
|
||||
this.update(this.recordingErrorValue);
|
||||
}
|
||||
@Input() set recordingError(value: any) {
|
||||
this.recordingErrorValue = value;
|
||||
this.update(this.recordingErrorValue);
|
||||
}
|
||||
|
||||
recordingErrorValue: RecordingInfo [] = [];
|
||||
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.update(this.recordingErrorValue);
|
||||
}
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
clear() {
|
||||
this.recordingErrorValue = null;
|
||||
this.update(null);
|
||||
}
|
||||
|
||||
update(value: any) {
|
||||
if (this.libService.recordingError.getValue() !== value) {
|
||||
this.libService.recordingError.next(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,6 +63,67 @@ export class ToolbarScreenshareButtonDirective implements AfterViewInit, OnDestr
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **recordingButton** directive allows show/hide the start/stop recording toolbar button.
|
||||
*
|
||||
* Default: `true`
|
||||
*
|
||||
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [toolbarRecordingButton]="false"></ov-videoconference>
|
||||
*
|
||||
* \
|
||||
* And it also can be used in the {@link ToolbarComponent}.
|
||||
* @example
|
||||
* <ov-toolbar [recordingButton]="false"></ov-toolbar>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[toolbarRecordingButton], ov-toolbar[recordingButton]'
|
||||
})
|
||||
export class ToolbarRecordingButtonDirective implements AfterViewInit, OnDestroy {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set toolbarRecordingButton(value: boolean) {
|
||||
this.recordingValue = value;
|
||||
this.update(this.recordingValue);
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set recordingButton(value: boolean) {
|
||||
this.recordingValue = value;
|
||||
this.update(this.recordingValue);
|
||||
}
|
||||
private recordingValue: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.update(this.recordingValue);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
private clear() {
|
||||
this.recordingValue = true;
|
||||
this.update(true);
|
||||
}
|
||||
|
||||
private update(value: boolean) {
|
||||
if (this.libService.recordingButton.getValue() !== value) {
|
||||
this.libService.recordingButton.next(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **fullscreenButton** directive allows show/hide the fullscreen toolbar button.
|
||||
*
|
||||
|
@ -392,7 +453,7 @@ export class ToolbarActivitiesPanelButtonDirective implements AfterViewInit, OnD
|
|||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set chatPanelButton(value: boolean) {
|
||||
@Input() set activitiesPanelButton(value: boolean) {
|
||||
this.toolbarActivitiesPanelValue = value;
|
||||
this.update(this.toolbarActivitiesPanelValue);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,15 @@
|
|||
"SUBTITLE": "为后人记录你的会议",
|
||||
"CONTENT_TITLE": "记录你的视频通话",
|
||||
"CONTENT_SUBTITLE": "当录音完成后,你将可以轻松地下载它",
|
||||
"STARTING": "开始录音"
|
||||
"STARTING": "开始录音",
|
||||
"STOPPING": "停止录制",
|
||||
"PLAY": "玩",
|
||||
"DELETE": "删除",
|
||||
"CANCEL": "取消",
|
||||
"DELETE_QUESTION": "您确定要删除录音吗",
|
||||
"DOWNLOAD": "下载",
|
||||
"RECORDINGS": "录制",
|
||||
"NO_MODERATOR": "只有主持人可以开始录音"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -60,7 +60,15 @@
|
|||
"SUBTITLE": "Zeichnen Sie Ihr Meeting für die Nachwelt auf",
|
||||
"CONTENT_TITLE": "Ihr Videogespräch aufzeichnen",
|
||||
"CONTENT_SUBTITLE": "Wenn die Aufzeichnung beendet ist, können Sie sie ganz einfach herunterladen",
|
||||
"STARTING": "Aufzeichnung starten"
|
||||
"STARTING": "Aufzeichnung starten",
|
||||
"STOPPING": "Aufnahme stoppen",
|
||||
"PLAY": "Spielen",
|
||||
"DELETE": "Löschen",
|
||||
"CANCEL": "Absagen",
|
||||
"DELETE_QUESTION": "Möchten Sie die Aufzeichnung wirklich löschen?",
|
||||
"DOWNLOAD": "Download",
|
||||
"RECORDINGS": "AUFZEICHNUNGEN",
|
||||
"NO_MODERATOR": "Nur der MODERATOR kann die Aufzeichnung starten"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -59,8 +59,16 @@
|
|||
"TITLE": "Recording",
|
||||
"SUBTITLE": "Record your meeting for posterity",
|
||||
"CONTENT_TITLE": "Record your video call",
|
||||
"CONTENT_SUBTITLE": "When recording has finished you will can download it with ease",
|
||||
"STARTING": "Starting recording"
|
||||
"CONTENT_SUBTITLE": "When recording has finished you will be able to download it with ease",
|
||||
"STARTING": "Starting recording",
|
||||
"STOPPING": "Stopping recording",
|
||||
"PLAY": "Play",
|
||||
"DELETE": "Delete",
|
||||
"CANCEL": "Cancel",
|
||||
"DELETE_QUESTION": "Are you sure you want to delete the recording?",
|
||||
"DOWNLOAD": "Download",
|
||||
"RECORDINGS": "RECORDINGS",
|
||||
"NO_MODERATOR": "Only the MODERATOR can start the recording"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -60,7 +60,26 @@
|
|||
"SUBTITLE": "Graba tus llamadas para la posteridad",
|
||||
"CONTENT_TITLE": "Graba tu video conferencia",
|
||||
"CONTENT_SUBTITLE": "Cuando la grabación haya finalizado, podrás descargarla con facilidad",
|
||||
"STARTING": "Iniciar grabación"
|
||||
"STARTING": "Iniciando grabación",
|
||||
"STOPPING": "Parando grabación",
|
||||
"PLAY": "Reproducir",
|
||||
"DELETE": "Borrar",
|
||||
"CANCEL": "Cancelar",
|
||||
"DELETE_QUESTION": "¿Estás seguro/a de que deseas borrar la grabación?",
|
||||
"DOWNLOAD": "Descargar",
|
||||
"RECORDINGS": "GRABACIONES",
|
||||
"NO_MODERATOR": "Sólo el MODERADOR puede iniciar la grabación"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
"SESSION": "Hubo un error al conectar a la sesión",
|
||||
"CONNECTION": "Sin conexión",
|
||||
"RECONNECT": "Intentando reconectar a la sesión...",
|
||||
"TOGGLE_CAMERA": "Hubo un error cambiando la cámara",
|
||||
"TOGGLE_MICROPHONE": "Hubo un error cambiando el micrófono",
|
||||
"SCREEN_SHARING": "Hubo un error compartiendo pantalla",
|
||||
"SCREEN_SUPPORT": "Tu navegador no soporta la pantalla compartida",
|
||||
"MEDIA_ACCESS": "No se ha podido acceder a tus dispositivos",
|
||||
"DEVICE_NOT_FOUND": "No se han encontrado dispositivos de audio o video. Por favor, conecta al menos uno."
|
||||
}
|
||||
}
|
|
@ -60,7 +60,16 @@
|
|||
"SUBTITLE": "Enregistrez votre réunion pour la postérité",
|
||||
"CONTENT_TITLE": "Enregistrez votre appel vidéo",
|
||||
"CONTENT_SUBTITLE": "Une fois l'enregistrement terminé, vous pourrez le télécharger facilement",
|
||||
"STARTING": "Début de l'enregistrement"
|
||||
"STARTING": "Début de l'enregistrement",
|
||||
"STOPPING": "Arrêt de l'enregistrement",
|
||||
"PLAY": "Jouer",
|
||||
"DELETE": "Effacer",
|
||||
"CANCEL": "Annuler",
|
||||
"DELETE_QUESTION": "Voulez-vous vraiment supprimer l'enregistrement ?",
|
||||
"DOWNLOAD": "Télécharger",
|
||||
"RECORDINGS": "ENREGISTREMENTS",
|
||||
"NO_MODERATOR": "Seul le MODERATEUR peut lancer l'enregistrement"
|
||||
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -60,7 +60,15 @@
|
|||
"SUBTITLE": "अपनी बैठक को भावी पीढ़ी के लिए रिकॉर्ड करें",
|
||||
"CONTENT_TITLE": "अपना वीडियो कॉल रिकॉर्ड करें",
|
||||
"CONTENT_SUBTITLE": "रिकॉर्डिंग समाप्त हो जाने पर आप इसे आसानी से डाउनलोड कर सकेंगे",
|
||||
"STARTING": "रिकॉर्डिंग शुरू कर रहा है"
|
||||
"STARTING": "रिकॉर्डिंग शुरू कर रहा है",
|
||||
"STOPPING": "रिकॉर्डिंग बंद करना",
|
||||
"PLAY": "खेलें",
|
||||
"DELETE": "मिटाना",
|
||||
"CANCEL": "रद्द करना",
|
||||
"DELETE_QUESTION": "क्या आप वाकई रिकॉर्डिंग हटाना चाहते हैं",
|
||||
"DOWNLOAD": "डाउनलोड",
|
||||
"RECORDINGS": "रिकॉर्डिंग",
|
||||
"NO_MODERATOR": "केवल मॉडरेटर ही रिकॉर्डिंग शुरू कर सकता है"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -60,7 +60,15 @@
|
|||
"SUBTITLE": "Registra la tua riunione per i posteri",
|
||||
"CONTENT_TITLE": "Registra la tua videochiamata",
|
||||
"CONTENT_SUBTITLE": "Al termine della registrazione potrete scaricarla con facilità",
|
||||
"STARTING": "Avvio della registrazione"
|
||||
"STARTING": "Avvio della registrazione",
|
||||
"STOPPING": "Interruzione della registrazione",
|
||||
"PLAY": "Giocare a",
|
||||
"DELETE": "Elimina",
|
||||
"CANCEL": "Annulla",
|
||||
"DELETE_QUESTION": "Sei sicuro di voler eliminare la registrazione?",
|
||||
"DOWNLOAD": "Scarica",
|
||||
"RECORDINGS": "REGISTRAZIONI",
|
||||
"NO_MODERATOR": "Solo il MODERATORE può avviare la registrazione"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -60,7 +60,15 @@
|
|||
"SUBTITLE": "会議を録音して後世に残す",
|
||||
"CONTENT_TITLE": "ビデオ通話を録音する",
|
||||
"CONTENT_SUBTITLE": "録音が完了したら、簡単にダウンロードできます",
|
||||
"STARTING": "録画開始"
|
||||
"STARTING": "録画開始",
|
||||
"STOPPING": "録音を停止します",
|
||||
"PLAY": "遊ぶ",
|
||||
"DELETE": "消去",
|
||||
"CANCEL": "キャンセル",
|
||||
"DELETE_QUESTION": "録音を削除してもよろしいですか",
|
||||
"DOWNLOAD": "ダウンロード",
|
||||
"RECORDINGS": "録画",
|
||||
"NO_MODERATOR": "録音を開始できるのは、モデレーターのみです"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -60,13 +60,21 @@
|
|||
"SUBTITLE": "Neem uw vergadering op voor het nageslacht",
|
||||
"CONTENT_TITLE": "Neem uw videogesprek op",
|
||||
"CONTENT_SUBTITLE": "Als de opname klaar is kunt u deze met gemak downloaden",
|
||||
"STARTING": "Beginnen met opnemen"
|
||||
"STARTING": "Beginnen met opnemen",
|
||||
"STOPPING": "Opname stoppen",
|
||||
"PLAY": "Toneelstuk",
|
||||
"DELETE": "Verwijderen",
|
||||
"CANCEL": "Annuleren",
|
||||
"DELETE_QUESTION": "Weet je zeker dat je de opname wilt verwijderen?",
|
||||
"DOWNLOAD": "Downloaden",
|
||||
"RECORDINGS": "OPNAME",
|
||||
"NO_MODERATOR": "Alleen de MOEDERATOR kan de opname starten"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
"SESSION": "Er is een fout opgetreden bij het verbinden met de sessie",
|
||||
"CONNECTION": "Verbinding verloren",
|
||||
"RECONNECT": "Oeps! Proberen opnieuw verbinding te maken met de sessie...",
|
||||
"RECONNECT": "Proberen opnieuw verbinding te maken met de sessie...",
|
||||
"TOGGLE_CAMERA": "Er is een fout opgetreden bij het overschakelen naar een andere camera",
|
||||
"TOGGLE_MICROPHONE": "Er is een fout opgetreden bij het overschakelen naar een microfoon",
|
||||
"SCREEN_SHARING": "Fout bij het delen van het scherm",
|
||||
|
|
|
@ -60,7 +60,15 @@
|
|||
"SUBTITLE": "Grave a sua reunião para a posteridade",
|
||||
"CONTENT_TITLE": "Grave a sua videochamada",
|
||||
"CONTENT_SUBTITLE": "Quando a gravação tiver terminado, poderá descarregá-la com facilidade",
|
||||
"STARTING": "Começar a gravação"
|
||||
"STARTING": "Começar a gravação",
|
||||
"STOPPING": "Parando a gravação",
|
||||
"PLAY": "Toque",
|
||||
"DELETE": "Excluir",
|
||||
"CANCEL": "Cancelar",
|
||||
"DELETE_QUESTION": "Tem certeza de que deseja excluir a gravação?",
|
||||
"DOWNLOAD": "Download",
|
||||
"RECORDINGS": "GRAVAÇÕES",
|
||||
"NO_MODERATOR": "Só o MODERADOR pode iniciar a gravação"
|
||||
}
|
||||
},
|
||||
"ERRORS": {
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export enum EffectType {
|
||||
NONE = 'NONE',
|
||||
BLUR = 'BLUR',
|
||||
IMAGE = 'IMAGE'
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface BackgroundEffect {
|
||||
id: string;
|
||||
type: EffectType;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export enum OpenViduEdition {
|
||||
CE = 'CE',
|
||||
PRO = 'PRO',
|
||||
ENTERPRISE = 'ENTERPRISE'
|
||||
}
|
|
@ -1,6 +1,14 @@
|
|||
import { Publisher, StreamManager } from 'openvidu-browser';
|
||||
import { VideoType } from './video-type.model';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export enum OpenViduRole {
|
||||
MODERATOR = 'MODERATOR',
|
||||
PUBLISHER = 'PUBLISHER'
|
||||
}
|
||||
|
||||
export interface StreamModel {
|
||||
/**
|
||||
* Whether the stream is available or not
|
||||
|
@ -329,6 +337,13 @@ export abstract class ParticipantAbstractModel {
|
|||
setMutedForcibly(muted: boolean) {
|
||||
this.isMutedForcibly = muted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getRole(): OpenViduRole {
|
||||
return <OpenViduRole>this.streams.get(VideoType.CAMERA)?.streamManager?.stream?.connection?.role;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
export enum RecordingStatus {
|
||||
STARTING = 'starting',
|
||||
STARTED = 'started',
|
||||
STOPPING = 'stopping',
|
||||
STOPPED = 'stopped',
|
||||
FAILED = 'failed',
|
||||
READY = 'ready'
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export enum RecordingStatus {
|
||||
STARTED = 'STARTED',
|
||||
STOPPED = 'STOPPED'
|
||||
export interface RecordingInfo {
|
||||
status: RecordingStatus;
|
||||
id?: string;
|
||||
name?: string;
|
||||
reason?: string;
|
||||
createdAt?: number;
|
||||
duration?: number;
|
||||
size?: string;
|
||||
url?: string
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface TokenModel {
|
||||
webcam: string;
|
||||
screen?: string;
|
||||
|
|
|
@ -27,18 +27,20 @@ import { CommonModule } from '@angular/common';
|
|||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
|
||||
import { ToolbarComponent } from './components/toolbar/toolbar.component';
|
||||
import { VideoComponent } from './components/video/video.component';
|
||||
import { ChatPanelComponent } from './components/panel/chat-panel/chat-panel.component';
|
||||
import { SessionComponent } from './components/session/session.component';
|
||||
import { LayoutComponent } from './components/layout/layout.component';
|
||||
import { StreamComponent } from './components/stream/stream.component';
|
||||
import { DialogTemplateComponent } from './components/material/dialog.component';
|
||||
import { DialogTemplateComponent } from './components/dialogs/dialog.component';
|
||||
import { RecordingDialogComponent } from './components/dialogs/recording-dialog.component';
|
||||
import { DeleteDialogComponent } from './components/dialogs/delete-recording.component';
|
||||
|
||||
import { LinkifyPipe } from './pipes/linkify.pipe';
|
||||
import { TranslatePipe } from './pipes/translate.pipe';
|
||||
import { StreamTypesEnabledPipe, ParticipantStreamsPipe } from './pipes/participant.pipe';
|
||||
import { DurationFromSecondsPipe } from './pipes/recording.pipe';
|
||||
|
||||
import { OpenViduAngularConfig } from './config/openvidu-angular.config';
|
||||
import { CdkOverlayContainer } from './config/custom-cdk-overlay';
|
||||
|
@ -55,6 +57,8 @@ import { DocumentService } from './services/document/document.service';
|
|||
import { LayoutService } from './services/layout/layout.service';
|
||||
import { PanelService } from './services/panel/panel.service';
|
||||
import { ParticipantService } from './services/participant/participant.service';
|
||||
import { RecordingService } from './services/recording/recording.service';
|
||||
|
||||
import { ParticipantPanelItemComponent } from './components/panel/participants-panel/participant-panel-item/participant-panel-item.component';
|
||||
import { ParticipantsPanelComponent } from './components/panel/participants-panel/participants-panel/participants-panel.component';
|
||||
import { VideoconferenceComponent } from './components/videoconference/videoconference.component';
|
||||
|
@ -78,8 +82,11 @@ import { RecordingActivityComponent } from './components/panel/activities-panel/
|
|||
LayoutComponent,
|
||||
StreamComponent,
|
||||
DialogTemplateComponent,
|
||||
RecordingDialogComponent,
|
||||
DeleteDialogComponent,
|
||||
LinkifyPipe,
|
||||
ParticipantStreamsPipe,
|
||||
DurationFromSecondsPipe,
|
||||
StreamTypesEnabledPipe,
|
||||
TranslatePipe,
|
||||
ParticipantPanelItemComponent,
|
||||
|
@ -137,7 +144,8 @@ import { RecordingActivityComponent } from './components/panel/activities-panel/
|
|||
ParticipantService,
|
||||
StorageService,
|
||||
TokenService,
|
||||
OpenViduService
|
||||
OpenViduService,
|
||||
RecordingService
|
||||
],
|
||||
exports: [
|
||||
VideoconferenceComponent,
|
||||
|
@ -155,12 +163,13 @@ import { RecordingActivityComponent } from './components/panel/activities-panel/
|
|||
AudioWaveComponent,
|
||||
PreJoinComponent,
|
||||
ParticipantStreamsPipe,
|
||||
DurationFromSecondsPipe,
|
||||
StreamTypesEnabledPipe,
|
||||
CommonModule,
|
||||
OpenViduAngularDirectiveModule,
|
||||
ApiDirectiveModule
|
||||
],
|
||||
entryComponents: [DialogTemplateComponent]
|
||||
entryComponents: [DialogTemplateComponent, RecordingDialogComponent, DeleteDialogComponent]
|
||||
})
|
||||
export class OpenViduAngularModule {
|
||||
static forRoot(config): ModuleWithProviders<OpenViduAngularModule> {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Pipe({
|
||||
name: 'duration'
|
||||
})
|
||||
export class DurationFromSecondsPipe implements PipeTransform {
|
||||
transform(durationInSeconds: number): string {
|
||||
if (durationInSeconds < 60) {
|
||||
return Math.floor(durationInSeconds) + 's';
|
||||
} else if (durationInSeconds < 3600) {
|
||||
return Math.floor(durationInSeconds / 60) + 'm ' + Math.floor(durationInSeconds % 60) + 's';
|
||||
} else {
|
||||
const hours = Math.floor(durationInSeconds / 3600);
|
||||
const minutes = Math.floor((durationInSeconds - hours * 3600) / 60);
|
||||
return hours + 'h ' + minutes + 'm';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { DialogTemplateComponent } from '../../components/material/dialog.component';
|
||||
|
||||
import { SafeResourceUrl } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { DeleteDialogComponent } from '../../components/dialogs/delete-recording.component';
|
||||
import { RecordingDialogComponent } from '../../components/dialogs/recording-dialog.component';
|
||||
import { DialogTemplateComponent } from '../../components/dialogs/dialog.component';
|
||||
import { INotificationOptions } from '../../models/notification-options.model';
|
||||
|
||||
/**
|
||||
|
@ -12,8 +15,8 @@ import { INotificationOptions } from '../../models/notification-options.model';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class ActionService {
|
||||
|
||||
private dialogRef: MatDialogRef<DialogTemplateComponent>;
|
||||
private dialogRef: MatDialogRef<DialogTemplateComponent | RecordingDialogComponent | DeleteDialogComponent>;
|
||||
private dialogSubscription: Subscription;
|
||||
constructor(private snackBar: MatSnackBar, public dialog: MatDialog) {}
|
||||
|
||||
launchNotification(options: INotificationOptions, callback): void {
|
||||
|
@ -36,9 +39,7 @@ export class ActionService {
|
|||
openDialog(titleMessage: string, descriptionMessage: string, allowClose = true) {
|
||||
try {
|
||||
this.closeDialog();
|
||||
|
||||
} catch (error) {
|
||||
|
||||
} finally {
|
||||
const config: MatDialogConfig = {
|
||||
minWidth: '250px',
|
||||
|
@ -46,13 +47,43 @@ export class ActionService {
|
|||
disableClose: !allowClose
|
||||
};
|
||||
this.dialogRef = this.dialog.open(DialogTemplateComponent, config);
|
||||
this.dialogRef.afterClosed().subscribe((result) => {
|
||||
this.dialogSubscription = this.dialogRef.afterClosed().subscribe((result) => {
|
||||
this.dialogRef = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
openDeleteRecordingDialog(succsessCallback) {
|
||||
try {
|
||||
this.closeDialog();
|
||||
} catch (error) {
|
||||
} finally {
|
||||
this.dialogRef = this.dialog.open(DeleteDialogComponent);
|
||||
|
||||
this.dialogSubscription = this.dialogRef.afterClosed().subscribe((result) => {
|
||||
if (result) {
|
||||
succsessCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
openRecordingPlayerDialog(src: SafeResourceUrl, type: string, allowClose = true) {
|
||||
try {
|
||||
this.closeDialog();
|
||||
} catch (error) {
|
||||
} finally {
|
||||
const config: MatDialogConfig = {
|
||||
minWidth: '250px',
|
||||
data: { src, type, showActionButtons: allowClose },
|
||||
disableClose: !allowClose
|
||||
};
|
||||
this.dialogRef = this.dialog.open(RecordingDialogComponent, config);
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
this.dialogRef.close();
|
||||
if (this.dialogSubscription) this.dialogSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Inject, Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { OpenViduAngularConfig, ParticipantFactoryFunction } from '../../config/openvidu-angular.config';
|
||||
import { RecordingInfo } from '../../models/recording.model';
|
||||
|
||||
// import { version } from '../../../../package.json';
|
||||
|
||||
|
@ -54,6 +55,14 @@ export class OpenViduAngularConfigService {
|
|||
participantItemMuteButtonObs: Observable<boolean>;
|
||||
backgroundEffectsButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
backgroundEffectsButtonObs: Observable<boolean>;
|
||||
recordingsList = <BehaviorSubject<RecordingInfo[]>>new BehaviorSubject([]);
|
||||
recordingsListObs: Observable<RecordingInfo[]>;
|
||||
recordingButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
recordingButtonObs: Observable<boolean>;
|
||||
recordingActivity = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
recordingActivityObs: Observable<boolean>;
|
||||
recordingError = <BehaviorSubject<any>>new BehaviorSubject(null);
|
||||
recordingErrorObs: Observable<any>;
|
||||
|
||||
constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) {
|
||||
this.configuration = config;
|
||||
|
@ -74,12 +83,17 @@ export class OpenViduAngularConfigService {
|
|||
this.activitiesPanelButtonObs = this.activitiesPanelButton.asObservable();
|
||||
this.displaySessionNameObs = this.displaySessionName.asObservable();
|
||||
this.displayLogoObs = this.displayLogo.asObservable();
|
||||
this.recordingButtonObs = this.recordingButton.asObservable();
|
||||
//Stream observables
|
||||
this.displayParticipantNameObs = this.displayParticipantName.asObservable();
|
||||
this.displayAudioDetectionObs = this.displayAudioDetection.asObservable();
|
||||
this.settingsButtonObs = this.settingsButton.asObservable();
|
||||
// Participant item observables
|
||||
this.participantItemMuteButtonObs = this.participantItemMuteButton.asObservable();
|
||||
// Recording activity observables
|
||||
this.recordingActivityObs = this.recordingActivity.asObservable();
|
||||
this.recordingsListObs = this.recordingsList.asObservable();
|
||||
this.recordingErrorObs = this.recordingError.asObservable();
|
||||
}
|
||||
|
||||
getConfig(): OpenViduAngularConfig {
|
||||
|
|
|
@ -12,12 +12,7 @@ import { CameraType } from '../../models/device.model';
|
|||
import { ScreenType, VideoType } from '../../models/video-type.model';
|
||||
import { ParticipantService } from '../participant/participant.service';
|
||||
import { TokenService } from '../token/token.service';
|
||||
|
||||
export enum OpenViduEdition {
|
||||
CE = 'CE',
|
||||
PRO = 'PRO',
|
||||
ENTERPRISE = 'ENTERPRISE'
|
||||
}
|
||||
import { OpenViduEdition } from '../../models/openvidu.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
|
@ -15,9 +15,10 @@ export class PanelService {
|
|||
protected log: ILogger;
|
||||
protected isChatOpened: boolean = false;
|
||||
protected isParticipantsOpened: boolean = false;
|
||||
protected isActivitiesOpened: boolean = false;
|
||||
private isExternalOpened: boolean = false;
|
||||
private externalType: string;
|
||||
protected _panelOpened = <BehaviorSubject<{ opened: boolean; type?: PanelType | string }>>new BehaviorSubject({ opened: false });
|
||||
protected _panelOpened = <BehaviorSubject<{ opened: boolean; type?: PanelType | string, expand?: string }>>new BehaviorSubject({ opened: false });
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -31,37 +32,46 @@ export class PanelService {
|
|||
* Open or close the panel type received. Calling this method with the panel opened and the same type panel, will close the panel.
|
||||
* If the type is differente, it will switch to the properly panel.
|
||||
*/
|
||||
togglePanel(type: PanelType | string) {
|
||||
togglePanel(type: PanelType | string, expand?: string) {
|
||||
this.log.d(`Toggling ${type} menu`);
|
||||
let opened: boolean;
|
||||
if (type === PanelType.CHAT) {
|
||||
this.isChatOpened = !this.isChatOpened;
|
||||
this.isParticipantsOpened = false;
|
||||
this.isExternalOpened = false;
|
||||
this.isActivitiesOpened = false
|
||||
opened = this.isChatOpened;
|
||||
} else if (type === PanelType.PARTICIPANTS) {
|
||||
this.isParticipantsOpened = !this.isParticipantsOpened;
|
||||
this.isChatOpened = false;
|
||||
this.isExternalOpened = false;
|
||||
this.isActivitiesOpened = false;
|
||||
opened = this.isParticipantsOpened;
|
||||
} else if (type === PanelType.ACTIVITIES) {
|
||||
this.isActivitiesOpened = !this.isActivitiesOpened;
|
||||
this.isChatOpened = false;
|
||||
this.isExternalOpened = false;
|
||||
this.isParticipantsOpened = false;
|
||||
opened = this.isActivitiesOpened;
|
||||
} else {
|
||||
this.log.d('Toggling external panel');
|
||||
this.isChatOpened = false;
|
||||
this.isParticipantsOpened = false;
|
||||
this.isActivitiesOpened = false;
|
||||
// Open when is close or is opened with another type
|
||||
this.isExternalOpened = !this.isExternalOpened || this.externalType !== type;
|
||||
this.externalType = !this.isExternalOpened ? '' : type;
|
||||
opened = this.isExternalOpened;
|
||||
}
|
||||
|
||||
this._panelOpened.next({ opened, type });
|
||||
this._panelOpened.next({ opened, type, expand });
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
isPanelOpened(): boolean {
|
||||
return this.isChatPanelOpened() || this.isParticipantsPanelOpened() || this.isExternalPanelOpened();
|
||||
return this.isChatPanelOpened() || this.isParticipantsPanelOpened() || this.isActivitiesPanelOpened() || this.isExternalPanelOpened();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,6 +81,7 @@ export class PanelService {
|
|||
this.isParticipantsOpened = false;
|
||||
this.isChatOpened = false;
|
||||
this.isExternalOpened = false;
|
||||
this.isActivitiesOpened = false;
|
||||
this._panelOpened.next({ opened: false });
|
||||
}
|
||||
|
||||
|
@ -88,6 +99,13 @@ export class PanelService {
|
|||
return this.isParticipantsOpened;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the activities panel is opened or not.
|
||||
*/
|
||||
isActivitiesPanelOpened(): boolean {
|
||||
return this.isActivitiesOpened;
|
||||
}
|
||||
|
||||
isExternalPanelOpened(): boolean {
|
||||
return this.isExternalOpened;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,10 @@ export class ParticipantService {
|
|||
return this.localParticipant.nickname;
|
||||
}
|
||||
|
||||
getMyRole(): string {
|
||||
return this.localParticipant.getRole();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { RecordingEvent } from 'openvidu-browser';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { RecordingStatus } from '../../models/recording.model';
|
||||
import { RecordingInfo, RecordingStatus } from '../../models/recording.model';
|
||||
import { ActionService } from '../action/action.service';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface RecordingInfo {
|
||||
status: RecordingStatus;
|
||||
id: string;
|
||||
name?: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
@ -23,30 +12,108 @@ export class RecordingService {
|
|||
/**
|
||||
* Recording status Observable which pushes the recording state in every update.
|
||||
*/
|
||||
recordingStatusObs: Observable<RecordingInfo>;
|
||||
private recordingStatus = <BehaviorSubject<RecordingInfo>>new BehaviorSubject(null);
|
||||
recordingStatusObs: Observable<{ info: RecordingInfo; time?: Date }>;
|
||||
|
||||
constructor() {
|
||||
private recordingTime: Date;
|
||||
private recordingTimeInterval: NodeJS.Timer;
|
||||
private currentRecording: RecordingInfo = { status: RecordingStatus.STOPPED };
|
||||
private recordingStatus = <BehaviorSubject<{ info: RecordingInfo; time?: Date }>>new BehaviorSubject(null);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param actionService
|
||||
* @param sanitizer
|
||||
*/
|
||||
constructor(private actionService: ActionService, private sanitizer: DomSanitizer) {
|
||||
this.recordingStatusObs = this.recordingStatus.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param status
|
||||
*/
|
||||
updateStatus(status: RecordingStatus) {
|
||||
this.currentRecording = {
|
||||
status: status
|
||||
};
|
||||
this.recordingStatus.next({ info: this.currentRecording });
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param event
|
||||
*/
|
||||
startRecording(event: RecordingEvent) {
|
||||
const info: RecordingInfo = {
|
||||
this.currentRecording = {
|
||||
status: RecordingStatus.STARTED,
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
reason: event.reason
|
||||
};
|
||||
this.recordingStatus.next(info);
|
||||
this.startRecordingTime();
|
||||
this.recordingStatus.next({ info: this.currentRecording, time: this.recordingTime });
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param event
|
||||
*/
|
||||
stopRecording(event: RecordingEvent) {
|
||||
const info: RecordingInfo = {
|
||||
status: RecordingStatus.STOPPED,
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
reason: event.reason
|
||||
};
|
||||
this.recordingStatus.next(info);
|
||||
this.currentRecording.status = RecordingStatus.STOPPED;
|
||||
this.currentRecording.reason = event.reason;
|
||||
this.recordingStatus.next({ info: this.currentRecording, time: null });
|
||||
this.stopRecordingTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the recording blob received as parameter. This parameter must be obtained from backend using the OpenVidu REST API
|
||||
* @param blob
|
||||
*/
|
||||
playRecording(blob: Blob) {
|
||||
const src = URL.createObjectURL(blob);
|
||||
this.actionService.openRecordingPlayerDialog(this.sanitizer.bypassSecurityTrustResourceUrl(src), blob.type, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the the recording blob received as second parameter and renamed with the value of the firts parameter.
|
||||
* This parameter must be obtained from backend using the OpenVidu REST API
|
||||
* @param fileName
|
||||
* @param blob
|
||||
*/
|
||||
downloadRecording(fileName: string, blob: Blob) {
|
||||
const data = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = data;
|
||||
link.download = `${fileName}.mp4`;
|
||||
|
||||
// this is necessary as link.click() does not work on the latest firefox
|
||||
link.dispatchEvent(
|
||||
new MouseEvent('click', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
view: window
|
||||
})
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
// For Firefox it is necessary to delay revoking the ObjectURL
|
||||
window.URL.revokeObjectURL(data);
|
||||
link.remove();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
private startRecordingTime() {
|
||||
this.recordingTime = new Date();
|
||||
this.recordingTime.setHours(0, 0, 0, 0);
|
||||
this.recordingTimeInterval = setInterval(() => {
|
||||
this.recordingTime.setSeconds(this.recordingTime.getSeconds() + 1);
|
||||
this.recordingTime = new Date(this.recordingTime.getTime());
|
||||
this.recordingStatus.next({ info: this.currentRecording, time: this.recordingTime });
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
private stopRecordingTime() {
|
||||
clearInterval(this.recordingTimeInterval);
|
||||
this.recordingTime = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ import * as nl from '../../lang/nl.json';
|
|||
import * as pt from '../../lang/pt.json';
|
||||
import { StorageService } from '../storage/storage.service';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
|
|
@ -19,10 +19,10 @@ export * from './lib/services/layout/layout.service';
|
|||
export * from './lib/services/panel/panel.service';
|
||||
export * from './lib/services/cdk-overlay/cdk-overlay.service';
|
||||
export * from './lib/services/storage/storage.service';
|
||||
export * from './lib/services/recording/recording.service';
|
||||
|
||||
// Components
|
||||
export * from './lib/components/videoconference/videoconference.component';
|
||||
// export * from './lib/components/user-settings/user-settings.component';
|
||||
export * from './lib/components/toolbar/toolbar.component';
|
||||
export * from './lib/components/panel/panel.component';
|
||||
export * from './lib/components/panel/chat-panel/chat-panel.component';
|
||||
|
@ -46,9 +46,11 @@ export * from './lib/models/notification-options.model';
|
|||
export * from './lib/models/token.model';
|
||||
export * from './lib/models/signal.model';
|
||||
export * from './lib/models/panel.model';
|
||||
export * from './lib/models/recording.model';
|
||||
|
||||
// Pipes
|
||||
export * from './lib/pipes/participant.pipe';
|
||||
export * from './lib/pipes/recording.pipe';
|
||||
|
||||
// Directives
|
||||
export * from './lib/directives/api/api.directive.module';
|
||||
|
@ -59,3 +61,5 @@ export * from './lib/directives/api/toolbar.directive';
|
|||
export * from './lib/directives/api/stream.directive';
|
||||
export * from './lib/directives/api/videoconference.directive';
|
||||
export * from './lib/directives/api/participant-panel-item.directive';
|
||||
export * from './lib/directives/api/activities-panel.directive';
|
||||
export * from './lib/directives/api/recording-activity.directive';
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
[videoMuted]="_videoMuted"
|
||||
[audioMuted]="_audioMuted"
|
||||
[toolbarScreenshareButton]="_toolbarScreenshareButton"
|
||||
[toolbarRecordingButton]="_toolbarRecordingButton"
|
||||
[toolbarFullscreenButton]="_toolbarFullscreenButton"
|
||||
[toolbarLeaveButton]="_toolbarLeaveButton"
|
||||
[toolbarActivitiesPanelButton]="_toolbarActivitiesPanelButton"
|
||||
[toolbarChatPanelButton]="_toolbarChatPanelButton"
|
||||
[toolbarParticipantsPanelButton]="_toolbarParticipantsPanelButton"
|
||||
[toolbarDisplayLogo]="_toolbarDisplayLogo"
|
||||
|
@ -17,6 +19,9 @@
|
|||
[streamDisplayAudioDetection]="_streamDisplayAudioDetection"
|
||||
[streamSettingsButton]="_streamSettingsButton"
|
||||
[participantPanelItemMuteButton]="_participantPanelItemMuteButton"
|
||||
[activitiesPanelRecordingActivity]="_activitiesPanelRecordingActivity"
|
||||
[recordingActivityRecordingsList]="_recordingActivityRecordingsList"
|
||||
[recordingActivityRecordingError]="_recordingActivityRecordingError"
|
||||
(onJoinButtonClicked)="_onJoinButtonClicked()"
|
||||
(onToolbarLeaveButtonClicked)="_onToolbarLeaveButtonClicked()"
|
||||
(onToolbarCameraButtonClicked)="_onToolbarCameraButtonClicked()"
|
||||
|
@ -24,7 +29,15 @@
|
|||
(onToolbarScreenshareButtonClicked)="_onToolbarScreenshareButtonClicked()"
|
||||
(onToolbarParticipantsPanelButtonClicked)="_onToolbarParticipantsPanelButtonClicked()"
|
||||
(onToolbarChatPanelButtonClicked)="_onToolbarChatPanelButtonClicked()"
|
||||
(onToolbarActivitiesPanelButtonClicked)="_onToolbarActivitiesPanelButtonClicked()"
|
||||
(onToolbarFullscreenButtonClicked)="_onToolbarFullscreenButtonClicked()"
|
||||
(onToolbarStartRecordingClicked)="onStartRecordingClicked('toolbar')"
|
||||
(onToolbarStopRecordingClicked)="onStopRecordingClicked('toolbar')"
|
||||
(onActivitiesPanelStartRecordingClicked)="onStartRecordingClicked('panel')"
|
||||
(onActivitiesPanelStopRecordingClicked)="onStopRecordingClicked('panel')"
|
||||
(onActivitiesPanelDownloadRecordingClicked)="_onActivitiesDownloadRecordingClicked($event)"
|
||||
(onActivitiesPanelDeleteRecordingClicked)="_onActivitiesDeleteRecordingClicked($event)"
|
||||
(onActivitiesPanelPlayRecordingClicked)="_onActivitiesPlayRecordingClicked($event)"
|
||||
(onSessionCreated)="_onSessionCreated($event)"
|
||||
(onParticipantCreated)="_onParticipantCreated($event)"
|
||||
></ov-videoconference>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
@use '@angular/material' as mat;
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
|
@ -20,13 +19,15 @@ $openvidu-components-warn: mat.define-palette(mat.$red-palette);
|
|||
|
||||
// Create the theme object. A theme consists of configurations for individual
|
||||
// theming systems such as "color" or "typography".
|
||||
$openvidu-components-theme: mat.define-light-theme((
|
||||
color: (
|
||||
primary: $openvidu-components-primary,
|
||||
accent: $openvidu-components-accent,
|
||||
warn: $openvidu-components-warn,
|
||||
)
|
||||
));
|
||||
$openvidu-components-theme: mat.define-light-theme(
|
||||
(
|
||||
color: (
|
||||
primary: $openvidu-components-primary,
|
||||
accent: $openvidu-components-accent,
|
||||
warn: $openvidu-components-warn
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Include theme styles for core and each component used in your app.
|
||||
// Alternatively, you can import and @include the theme mixins for each component
|
||||
|
@ -37,8 +38,8 @@ $openvidu-components-theme: mat.define-light-theme((
|
|||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(https://fonts.gstatic.com/s/materialicons/v38/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
|
||||
}
|
||||
src: url(https://fonts.gstatic.com/s/materialicons/v129/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
|
@ -56,13 +57,19 @@ $openvidu-components-theme: mat.define-light-theme((
|
|||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
|
||||
html, body { height: 100%; overflow: hidden;}
|
||||
body { margin: 0; font-family: 'Roboto','RobotoDraft',Helvetica,Arial,sans-serif;}
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Roboto', 'RobotoDraft', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
#poster-text {
|
||||
padding: 0px !important;
|
||||
}
|
||||
ov-chat-panel .text-info {
|
||||
margin: 3px auto !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import { Component, ElementRef, Input, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { ILogger, LoggerService, OpenViduService } from 'openvidu-angular';
|
||||
import { ILogger, LoggerService, OpenViduService, TokenModel, ParticipantAbstractModel, RecordingInfo } from 'openvidu-angular';
|
||||
import { Session } from 'openvidu-browser';
|
||||
import { ParticipantAbstractModel } from '../../../projects/openvidu-angular/src/lib/models/participant.model';
|
||||
|
||||
export interface TokenModel {
|
||||
webcam: string;
|
||||
screen: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -45,6 +39,10 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
* @internal
|
||||
*/
|
||||
_toolbarScreenshareButton: boolean = true;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_toolbarRecordingButton: boolean = true;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -61,6 +59,10 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
* @internal
|
||||
*/
|
||||
_toolbarChatPanelButton: boolean = true;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_toolbarActivitiesPanelButton: boolean = true;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -89,6 +91,19 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
* @internal
|
||||
*/
|
||||
_participantPanelItemMuteButton: boolean = true;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_recordingActivityRecordingError: any = null;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_activitiesPanelRecordingActivity: boolean = true;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_recordingActivityRecordingsList: RecordingInfo[] = [];
|
||||
|
||||
/**
|
||||
* The **minimal** attribute applies a minimal UI hiding all controls except for cam and mic.
|
||||
|
@ -167,6 +182,21 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
@Input() set toolbarScreenshareButton(value: string | boolean) {
|
||||
this._toolbarScreenshareButton = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **toolbarRecordingButton** attribute allows show/hide the start/stop recording toolbar button.
|
||||
*
|
||||
* Default: `true`
|
||||
*
|
||||
* <div class="warn-container">
|
||||
* <span>WARNING</span>: If you want to use this parameter to OpenVidu Web Component statically, you have to replace the <strong>camelCase</strong> with a <strong>hyphen between words</strong>.</div>
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent toolbar-recording-button="false"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set toolbarRecordingButton(value: string | boolean) {
|
||||
this._toolbarRecordingButton = this.castToBoolean(value);
|
||||
}
|
||||
/**
|
||||
* The **toolbarFullscreenButton** attribute allows show/hide the fullscreen toolbar button.
|
||||
*
|
||||
|
@ -224,6 +254,21 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
@Input() set toolbarChatPanelButton(value: string | boolean) {
|
||||
this._toolbarChatPanelButton = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **toolbarActivitiesPanelButton** attribute allows show/hide the activities panel toolbar button.
|
||||
*
|
||||
* Default: `true`
|
||||
*
|
||||
* <div class="warn-container">
|
||||
* <span>WARNING</span>: If you want to use this parameter to OpenVidu Web Component statically, you have to replace the <strong>camelCase</strong> with a <strong>hyphen between words</strong>.</div>
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent toolbar-activities-panel-button="false"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set toolbarActivitiesPanelButton(value: string | boolean) {
|
||||
this._toolbarActivitiesPanelButton = this.castToBoolean(value);
|
||||
}
|
||||
/**
|
||||
* The **toolbarParticipantsPanelButton** attribute allows show/hide the participants panel toolbar button.
|
||||
*
|
||||
|
@ -323,6 +368,42 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
this._participantPanelItemMuteButton = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **recordingActivityRecordingError** attribute allows to show any possible error with the recording in the {@link RecordingActivityComponent}.
|
||||
*
|
||||
* Default: `true`
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent recording-activity-recording-error="false"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set recordingActivityRecordingError(value: any) {
|
||||
this._recordingActivityRecordingError = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The **activitiesPanelRecordingActivity** attribute allows show/hide the recording activity in {@link ActivitiesPanelComponent}.
|
||||
*
|
||||
* Default: `true`
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent activity-panel-recording-activity="false"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set activitiesPanelRecordingActivity(value: string | boolean) {
|
||||
this._activitiesPanelRecordingActivity = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **recordingActivityRecordingList** attribute allows show to show the recordings available for the session in {@link RecordingActivityComponent}.
|
||||
*
|
||||
* Default: `[]`
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent recording-activity-recordings-list="recordingsList"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set recordingActivityRecordingsList(value: RecordingInfo[]) {
|
||||
this._recordingActivityRecordingsList = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when join button (in prejoin page) has been clicked.
|
||||
*/
|
||||
|
@ -363,6 +444,46 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
*/
|
||||
@Output() onToolbarChatPanelButtonClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when activities panel button has been clicked.
|
||||
*/
|
||||
@Output() onToolbarActivitiesPanelButtonClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
@Output() onToolbarStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button is clicked from {@link ToolbarComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onToolbarStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when start recording button is clicked {@link ActivitiesPanelComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelStartRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
/**
|
||||
* Provides event notifications that fire when stop recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
* The recording should be stopped using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelStopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when download recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
* The recording should be downloaded using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelDownloadRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when delete recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
* The recording should be deleted using the REST API.
|
||||
*/
|
||||
@Output() onActivitiesPanelDeleteRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when play recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||
*/
|
||||
@Output() onActivitiesPanelPlayRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
/**
|
||||
* Provides event notifications that fire when OpenVidu Session is created.
|
||||
* See {@link https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/Session.html openvidu-browser Session}.
|
||||
|
@ -393,6 +514,7 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
/**
|
||||
* @example
|
||||
* <openvidu-webcomponent tokens='{"webcam":"TOKEN1", "screen":"TOKEN2"}'></openvidu-webcomponent>
|
||||
* * <openvidu-webcomponent tokens='TOKEN'></openvidu-webcomponent>
|
||||
*/
|
||||
@Input('tokens')
|
||||
set tokens(value: TokenModel | string) {
|
||||
|
@ -455,12 +577,56 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
_onToolbarChatPanelButtonClicked() {
|
||||
this.onToolbarChatPanelButtonClicked.emit();
|
||||
}
|
||||
|
||||
_onToolbarActivitiesPanelButtonClicked() {
|
||||
this.onToolbarActivitiesPanelButtonClicked.emit();
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onToolbarFullscreenButtonClicked() {
|
||||
this.onToolbarFullscreenButtonClicked.emit();
|
||||
}
|
||||
onStartRecordingClicked(from: string) {
|
||||
if (from === 'toolbar') {
|
||||
this.onToolbarStartRecordingClicked.emit();
|
||||
} else if (from === 'panel') {
|
||||
this.onActivitiesPanelStartRecordingClicked.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onStopRecordingClicked(from: string) {
|
||||
if (from === 'toolbar') {
|
||||
this.onToolbarStopRecordingClicked.emit();
|
||||
} else if (from === 'panel') {
|
||||
this.onActivitiesPanelStopRecordingClicked.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onActivitiesDownloadRecordingClicked(recordingId: string) {
|
||||
this.onActivitiesPanelDownloadRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onActivitiesDeleteRecordingClicked(recordingId: string) {
|
||||
this.onActivitiesPanelDeleteRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_onActivitiesPlayRecordingClicked(recordingId: string) {
|
||||
this.onActivitiesPanelPlayRecordingClicked.emit(recordingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue