mirror of https://github.com/OpenVidu/openvidu.git
openvidu-testapp local recording
parent
36d5018507
commit
bcf636b507
|
@ -11,9 +11,12 @@ import { TestSessionsComponent } from './components/test-sessions/test-sessions.
|
||||||
import { TestApirestComponent } from './components/test-apirest/test-apirest.component';
|
import { TestApirestComponent } from './components/test-apirest/test-apirest.component';
|
||||||
import { OpenviduInstanceComponent } from './components/openvidu-instance/openvidu-instance.component';
|
import { OpenviduInstanceComponent } from './components/openvidu-instance/openvidu-instance.component';
|
||||||
import { ExtensionDialogComponent } from './components/openvidu-instance/extension-dialog.component';
|
import { ExtensionDialogComponent } from './components/openvidu-instance/extension-dialog.component';
|
||||||
|
import { LocalRecordingDialogComponent } from './components/test-sessions/local-recording-dialog.component';
|
||||||
|
|
||||||
import { OpenviduRestService } from './services/openvidu-rest.service';
|
import { OpenviduRestService } from './services/openvidu-rest.service';
|
||||||
import { OpenviduParamsService } from './services/openvidu-params.service';
|
import { OpenviduParamsService } from './services/openvidu-params.service';
|
||||||
import { TestFeedService } from './services/test-feed.service';
|
import { TestFeedService } from './services/test-feed.service';
|
||||||
|
import { MuteSubscribersService } from './services/mute-subscribers.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -21,7 +24,8 @@ import { TestFeedService } from './services/test-feed.service';
|
||||||
OpenviduInstanceComponent,
|
OpenviduInstanceComponent,
|
||||||
TestSessionsComponent,
|
TestSessionsComponent,
|
||||||
TestApirestComponent,
|
TestApirestComponent,
|
||||||
ExtensionDialogComponent
|
ExtensionDialogComponent,
|
||||||
|
LocalRecordingDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -34,9 +38,13 @@ import { TestFeedService } from './services/test-feed.service';
|
||||||
providers: [
|
providers: [
|
||||||
OpenviduRestService,
|
OpenviduRestService,
|
||||||
OpenviduParamsService,
|
OpenviduParamsService,
|
||||||
TestFeedService
|
TestFeedService,
|
||||||
|
MuteSubscribersService
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
ExtensionDialogComponent,
|
||||||
|
LocalRecordingDialogComponent
|
||||||
],
|
],
|
||||||
entryComponents: [ExtensionDialogComponent],
|
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -2,10 +2,14 @@ import {
|
||||||
Component, Input, HostListener, ChangeDetectorRef, SimpleChanges, ElementRef, ViewChild,
|
Component, Input, HostListener, ChangeDetectorRef, SimpleChanges, ElementRef, ViewChild,
|
||||||
OnInit, OnDestroy, OnChanges
|
OnInit, OnDestroy, OnChanges
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { OpenVidu, Session, Subscriber, Publisher, Stream, Connection } from 'openvidu-browser';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { MatDialog } from '@angular/material';
|
|
||||||
|
import { OpenVidu, Session, Subscriber, Publisher, Stream, Connection, LocalRecorder } from 'openvidu-browser';
|
||||||
|
import { MatDialog, MatDialogRef } from '@angular/material';
|
||||||
import { ExtensionDialogComponent } from './extension-dialog.component';
|
import { ExtensionDialogComponent } from './extension-dialog.component';
|
||||||
|
import { LocalRecordingDialogComponent } from '../test-sessions/local-recording-dialog.component';
|
||||||
import { TestFeedService } from '../../services/test-feed.service';
|
import { TestFeedService } from '../../services/test-feed.service';
|
||||||
|
import { MuteSubscribersService } from '../../services/mute-subscribers.service';
|
||||||
|
|
||||||
declare var $: any;
|
declare var $: any;
|
||||||
|
|
||||||
|
@ -94,10 +98,17 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
openviduError: any;
|
openviduError: any;
|
||||||
|
|
||||||
|
private publisherRecorder: LocalRecorder;
|
||||||
|
private publisherRecording = false;
|
||||||
|
private publisherPaused = false;
|
||||||
|
private muteSubscribersSubscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private changeDetector: ChangeDetectorRef,
|
private changeDetector: ChangeDetectorRef,
|
||||||
private extensionDialog: MatDialog,
|
private extensionDialog: MatDialog,
|
||||||
private testFeedService: TestFeedService
|
private recordDialog: MatDialog,
|
||||||
|
private testFeedService: TestFeedService,
|
||||||
|
private muteSubscribersService: MuteSubscribersService,
|
||||||
) {
|
) {
|
||||||
this.generateSessionInfo();
|
this.generateSessionInfo();
|
||||||
}
|
}
|
||||||
|
@ -116,6 +127,13 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
if (this.sessionConf.startSession) {
|
if (this.sessionConf.startSession) {
|
||||||
this.joinSession();
|
this.joinSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.muteSubscribersSubscription = this.muteSubscribersService.mutedEvent$.subscribe(
|
||||||
|
muteOrUnmute => {
|
||||||
|
Object.keys(this.subscribers).forEach((key) => {
|
||||||
|
this.subscribers[key].videoElement.muted = muteOrUnmute;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
@ -128,6 +146,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
if (!!this.muteSubscribersSubscription) { this.muteSubscribersSubscription.unsubscribe(); }
|
||||||
this.leaveSession();
|
this.leaveSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,18 +278,53 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
this.unpublished ? this.publishIcon = 'play_arrow' : this.publishIcon = 'stop';
|
this.unpublished ? this.publishIcon = 'play_arrow' : this.publishIcon = 'stop';
|
||||||
}
|
}
|
||||||
|
|
||||||
private appendUserData(videoElement, connection): void {
|
private appendSubscriberData(videoElement: HTMLVideoElement, connection: Connection): void {
|
||||||
const dataNode = document.createElement('div');
|
const dataNode = document.createElement('div');
|
||||||
dataNode.className = 'data-node';
|
dataNode.className = 'data-node';
|
||||||
dataNode.id = 'data-' + this.session.connection.connectionId + '-' + connection.connectionId;
|
dataNode.id = 'data-' + this.session.connection.connectionId + '-' + connection.connectionId;
|
||||||
dataNode.innerHTML = '<p class="name">' + connection.data + '</p>' +
|
dataNode.innerHTML = '<p class="name">' + connection.data + '</p>' +
|
||||||
'<button id="sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId + '" class="sub-btn">' +
|
'<button id="sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
||||||
'<mat-icon id="icon-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
'" class="sub-btn" title="Subscribe/Unsubscribe"><mat-icon id="icon-' + this.session.connection.connectionId +
|
||||||
'" aria-label="Subscribe or unsubscribe" class="mat-icon material-icons" role="img"' +
|
'-' + connection.connectionId + '" aria-label="Subscribe or unsubscribe" class="mat-icon material-icons" role="img"' +
|
||||||
'aria-hidden="true">notifications</mat-icon></button>';
|
'aria-hidden="true">notifications</mat-icon></button>' +
|
||||||
|
'<button id="record-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
||||||
|
'" class="sub-btn rec-btn" title="Record"><mat-icon id="record-icon-' +
|
||||||
|
this.session.connection.connectionId + '-' + connection.connectionId +
|
||||||
|
'" aria-label="Start/Stop recording" class="mat-icon material-icons" role="img"' +
|
||||||
|
'aria-hidden="true">fiber_manual_record</mat-icon></button>' +
|
||||||
|
'<button style="display:none" id="pause-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
||||||
|
'" class="sub-btn rec-btn" title="Pause/Resume"><mat-icon id="pause-icon-' +
|
||||||
|
this.session.connection.connectionId + '-' + connection.connectionId +
|
||||||
|
'" aria-label="Pause/Resume recording" class="mat-icon material-icons" role="img"' +
|
||||||
|
'aria-hidden="true">pause</mat-icon></button>';
|
||||||
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
|
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
|
||||||
document.getElementById('sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId).addEventListener('click',
|
document.getElementById('sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId).addEventListener('click',
|
||||||
this.subUnsubFromSubscriber.bind(this, connection.connectionId));
|
this.subUnsubFromSubscriber.bind(this, connection.connectionId));
|
||||||
|
document.getElementById('record-btn-' + this.session.connection.connectionId + '-' + connection.connectionId).addEventListener('click',
|
||||||
|
this.recordSubscriber.bind(this, connection.connectionId));
|
||||||
|
document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connection.connectionId).addEventListener('click',
|
||||||
|
this.pauseSubscriber.bind(this, connection.connectionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private appendPublisherData(videoElement: HTMLVideoElement): void {
|
||||||
|
const dataNode = document.createElement('div');
|
||||||
|
dataNode.className = 'data-node';
|
||||||
|
dataNode.id = 'data-' + this.session.connection.connectionId + '-' + this.session.connection.connectionId;
|
||||||
|
dataNode.innerHTML =
|
||||||
|
'<button id="local-record-btn-' + this.session.connection.connectionId +
|
||||||
|
'" class="sub-btn rec-btn publisher-rec-btn" title="Record"><mat-icon id="local-record-icon-' + this.session.connection.connectionId +
|
||||||
|
'" aria-label="Start/Stop local recording" class="mat-icon material-icons" role="img" aria-hidden="true">' +
|
||||||
|
'fiber_manual_record</mat-icon></button>' +
|
||||||
|
'<button style="display:none" id="local-pause-btn-' + this.session.connection.connectionId +
|
||||||
|
'" class="sub-btn rec-btn publisher-rec-btn" title="Pause/Resume">' +
|
||||||
|
'<mat-icon id="local-pause-icon-' + this.session.connection.connectionId +
|
||||||
|
'" aria-label="Pause/Resume local recording" class="mat-icon material-icons" role="img" aria-hidden="true">' +
|
||||||
|
'pause</mat-icon></button>';
|
||||||
|
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
|
||||||
|
document.getElementById('local-record-btn-' + this.session.connection.connectionId).addEventListener('click',
|
||||||
|
this.recordPublisher.bind(this));
|
||||||
|
document.getElementById('local-pause-btn-' + this.session.connection.connectionId).addEventListener('click',
|
||||||
|
this.pausePublisher.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeUserData(connectionId: string): void {
|
private removeUserData(connectionId: string): void {
|
||||||
|
@ -369,11 +423,108 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recordPublisher(): void {
|
||||||
|
if (!this.publisherRecording) {
|
||||||
|
this.publisherRecorder = this.OV.initLocalRecorder(this.publisher.stream);
|
||||||
|
this.publisherRecorder.record();
|
||||||
|
this.publisherRecording = true;
|
||||||
|
document.getElementById('local-record-icon-' + this.session.connection.connectionId).innerHTML = 'stop';
|
||||||
|
document.getElementById('local-pause-btn-' + this.session.connection.connectionId).style.display = 'block';
|
||||||
|
} else {
|
||||||
|
this.publisherRecorder.stop()
|
||||||
|
.then(() => {
|
||||||
|
let dialogRef: MatDialogRef<LocalRecordingDialogComponent>;
|
||||||
|
dialogRef = this.recordDialog.open(LocalRecordingDialogComponent, {
|
||||||
|
disableClose: true,
|
||||||
|
data: {
|
||||||
|
recorder: this.publisherRecorder
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef.componentInstance.myReference = dialogRef;
|
||||||
|
|
||||||
|
dialogRef.afterOpen().subscribe(() => {
|
||||||
|
this.afterOpenPreview(this.publisherRecorder);
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
this.afterClosePreview(this.publisherRecorder);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error stopping LocalRecorder: ' + error);
|
||||||
|
});
|
||||||
|
this.restartPublisherRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pausePublisher(): void {
|
||||||
|
if (!this.publisherPaused) {
|
||||||
|
this.publisherRecorder.pause();
|
||||||
|
document.getElementById('local-pause-icon-' + this.session.connection.connectionId).innerHTML = 'play_arrow';
|
||||||
|
} else {
|
||||||
|
this.publisherRecorder.resume();
|
||||||
|
document.getElementById('local-pause-icon-' + this.session.connection.connectionId).innerHTML = 'pause';
|
||||||
|
}
|
||||||
|
this.publisherPaused = !this.publisherPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordSubscriber(connectionId: string): void {
|
||||||
|
const subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
||||||
|
const recording = this.subscribers[connectionId].recording;
|
||||||
|
if (!recording) {
|
||||||
|
this.subscribers[connectionId].recorder = this.OV.initLocalRecorder(subscriber.stream);
|
||||||
|
this.subscribers[connectionId].recorder.record();
|
||||||
|
this.subscribers[connectionId].recording = true;
|
||||||
|
document.getElementById('record-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'stop';
|
||||||
|
document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connectionId).style.display = 'block';
|
||||||
|
} else {
|
||||||
|
this.subscribers[connectionId].recorder.stop()
|
||||||
|
.then(() => {
|
||||||
|
let dialogRef: MatDialogRef<LocalRecordingDialogComponent>;
|
||||||
|
dialogRef = this.recordDialog.open(LocalRecordingDialogComponent, {
|
||||||
|
disableClose: true,
|
||||||
|
data: {
|
||||||
|
recorder: this.subscribers[connectionId].recorder
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef.componentInstance.myReference = dialogRef;
|
||||||
|
|
||||||
|
dialogRef.afterOpen().subscribe(() => {
|
||||||
|
this.afterOpenPreview(this.subscribers[connectionId].recorder);
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
this.afterClosePreview(this.subscribers[connectionId].recorder);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error stopping LocalRecorder: ' + error);
|
||||||
|
});
|
||||||
|
this.restartSubscriberRecord(connectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pauseSubscriber(connectionId: string): void {
|
||||||
|
const subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
||||||
|
const subscriberPaused = this.subscribers[connectionId].paused;
|
||||||
|
if (!subscriberPaused) {
|
||||||
|
this.subscribers[connectionId].recorder.pause();
|
||||||
|
document.getElementById('pause-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'play_arrow';
|
||||||
|
} else {
|
||||||
|
this.subscribers[connectionId].recorder.resume();
|
||||||
|
document.getElementById('pause-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'pause';
|
||||||
|
}
|
||||||
|
this.subscribers[connectionId].paused = !this.subscribers[connectionId].paused;
|
||||||
|
}
|
||||||
|
|
||||||
publishUnpublish(): void {
|
publishUnpublish(): void {
|
||||||
if (this.unpublished) {
|
if (this.unpublished) {
|
||||||
this.session.publish(this.publisher);
|
this.session.publish(this.publisher);
|
||||||
} else {
|
} else {
|
||||||
|
if (!!this.publisherRecorder && this.publisherRecording) {
|
||||||
|
this.publisherRecorder.clean();
|
||||||
|
}
|
||||||
this.session.unpublish(this.publisher);
|
this.session.unpublish(this.publisher);
|
||||||
|
this.removeUserData(this.session.connection.connectionId);
|
||||||
|
this.restartPublisherRecord();
|
||||||
}
|
}
|
||||||
this.unpublished = !this.unpublished;
|
this.unpublished = !this.unpublished;
|
||||||
this.updatePublishIcon();
|
this.updatePublishIcon();
|
||||||
|
@ -383,6 +534,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
if (!this.unpublished) {
|
if (!this.unpublished) {
|
||||||
this.session.unpublish(this.publisher);
|
this.session.unpublish(this.publisher);
|
||||||
|
this.removeUserData(this.session.connection.connectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
let screenChange;
|
let screenChange;
|
||||||
|
@ -448,9 +600,15 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
subUnsubFromSubscriber(connectionId: string) {
|
subUnsubFromSubscriber(connectionId: string) {
|
||||||
let subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
let subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
||||||
if (this.subscribers[connectionId].subbed) {
|
if (this.subscribers[connectionId].subbed) {
|
||||||
|
if (!!this.subscribers[connectionId].recorder && this.subscribers[connectionId].recording) {
|
||||||
|
this.subscribers[connectionId].recorder.clean();
|
||||||
|
}
|
||||||
this.session.unsubscribe(subscriber);
|
this.session.unsubscribe(subscriber);
|
||||||
|
this.restartSubscriberRecord(connectionId);
|
||||||
document.getElementById('data-' + this.session.connection.connectionId + '-' + connectionId).style.marginLeft = '0';
|
document.getElementById('data-' + this.session.connection.connectionId + '-' + connectionId).style.marginLeft = '0';
|
||||||
document.getElementById('icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'notifications_off';
|
document.getElementById('icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'notifications_off';
|
||||||
|
document.getElementById('record-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
||||||
|
document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
||||||
} else {
|
} else {
|
||||||
subscriber = this.session.subscribe(subscriber.stream, 'remote-vid-' + this.session.connection.connectionId);
|
subscriber = this.session.subscribe(subscriber.stream, 'remote-vid-' + this.session.connection.connectionId);
|
||||||
this.subscribers[connectionId].subscriber = subscriber;
|
this.subscribers[connectionId].subscriber = subscriber;
|
||||||
|
@ -459,11 +617,12 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
$(e.element).css({ 'background-color': '#4d4d4d' });
|
$(e.element).css({ 'background-color': '#4d4d4d' });
|
||||||
$(e.element).attr('poster', 'assets/images/volume.png');
|
$(e.element).attr('poster', 'assets/images/volume.png');
|
||||||
}
|
}
|
||||||
this.removeUserData(connectionId);
|
this.subscribers[connectionId].videoElement = e.element;
|
||||||
this.appendUserData(e.element, subscriber.stream.connection);
|
|
||||||
this.updateEventList('videoElementCreated', e.element.id);
|
this.updateEventList('videoElementCreated', e.element.id);
|
||||||
});
|
});
|
||||||
subscriber.on('videoPlaying', (e) => {
|
subscriber.on('videoPlaying', (e) => {
|
||||||
|
this.removeUserData(connectionId);
|
||||||
|
this.appendSubscriberData(e.element, subscriber.stream.connection);
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
this.updateEventList('videoPlaying', e.element.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -477,21 +636,29 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
if (this.subscribeTo) {
|
if (this.subscribeTo) {
|
||||||
const subscriber: Subscriber = session.subscribe(event.stream, 'remote-vid-' + session.connection.connectionId);
|
const subscriber: Subscriber = session.subscribe(event.stream, 'remote-vid-' + session.connection.connectionId);
|
||||||
|
this.subscribers[subscriber.stream.connection.connectionId] = {
|
||||||
|
'subscriber': subscriber,
|
||||||
|
'subbed': true,
|
||||||
|
'recorder': undefined,
|
||||||
|
'recording': false,
|
||||||
|
'paused': false,
|
||||||
|
'videoElement': undefined
|
||||||
|
};
|
||||||
subscriber.on('videoElementCreated', (e) => {
|
subscriber.on('videoElementCreated', (e) => {
|
||||||
if (!event.stream.getRecvVideo()) {
|
if (!event.stream.getRecvVideo()) {
|
||||||
$(e.element).css({ 'background-color': '#4d4d4d' });
|
$(e.element).css({ 'background-color': '#4d4d4d' });
|
||||||
$(e.element).attr('poster', 'assets/images/volume.png');
|
$(e.element).attr('poster', 'assets/images/volume.png');
|
||||||
}
|
}
|
||||||
this.appendUserData(e.element, subscriber.stream.connection);
|
this.subscribers[subscriber.stream.connection.connectionId].videoElement = e.element;
|
||||||
this.updateEventList('videoElementCreated', e.element.id);
|
this.updateEventList('videoElementCreated', e.element.id);
|
||||||
});
|
});
|
||||||
subscriber.on('videoPlaying', (e) => {
|
subscriber.on('videoPlaying', (e) => {
|
||||||
|
this.appendSubscriberData(e.element, subscriber.stream.connection);
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
this.updateEventList('videoPlaying', e.element.id);
|
||||||
});
|
});
|
||||||
subscriber.on('videoElementDestroyed', (e) => {
|
subscriber.on('videoElementDestroyed', (e) => {
|
||||||
this.updateEventList('videoElementDestroyed', '(Subscriber)');
|
this.updateEventList('videoElementDestroyed', '(Subscriber)');
|
||||||
});
|
});
|
||||||
this.subscribers[subscriber.stream.connection.connectionId] = { 'subscriber': subscriber, 'subbed': true };
|
|
||||||
}
|
}
|
||||||
this.updateEventList('streamCreated', event.stream.connection.connectionId);
|
this.updateEventList('streamCreated', event.stream.connection.connectionId);
|
||||||
});
|
});
|
||||||
|
@ -546,12 +713,13 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
this.updateEventList('accessDenied', '');
|
this.updateEventList('accessDenied', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
publisher.on('videoPlaying', (e) => {
|
publisher.on('videoPlaying', (e) => {
|
||||||
|
this.appendPublisherData(e.element);
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
this.updateEventList('videoPlaying', e.element.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
publisher.on('remoteVideoPlaying', (e) => {
|
publisher.on('remoteVideoPlaying', (e) => {
|
||||||
|
this.appendPublisherData(e.element);
|
||||||
this.updateEventList('remoteVideoPlaying', e.element.id);
|
this.updateEventList('remoteVideoPlaying', e.element.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -568,4 +736,48 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private afterOpenPreview(recorder: LocalRecorder): void {
|
||||||
|
this.muteSubscribersService.updateMuted(true);
|
||||||
|
recorder.preview('local-recorder-preview').controls = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private afterClosePreview(recorder: LocalRecorder): void {
|
||||||
|
this.muteSubscribersService.updateMuted(false);
|
||||||
|
recorder.clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
private restartPublisherRecord(): void {
|
||||||
|
let el: HTMLElement = document.getElementById('local-record-icon-' + this.session.connection.connectionId);
|
||||||
|
if (!!el) {
|
||||||
|
el.innerHTML = 'fiber_manual_record';
|
||||||
|
}
|
||||||
|
el = document.getElementById('local-pause-icon-' + this.session.connection.connectionId);
|
||||||
|
if (!!el) {
|
||||||
|
el.innerHTML = 'pause';
|
||||||
|
}
|
||||||
|
el = document.getElementById('local-pause-btn-' + this.session.connection.connectionId);
|
||||||
|
if (!!el) {
|
||||||
|
el.style.display = 'none';
|
||||||
|
}
|
||||||
|
this.publisherPaused = false;
|
||||||
|
this.publisherRecording = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private restartSubscriberRecord(connectionId: string): void {
|
||||||
|
let el: HTMLElement = document.getElementById('record-icon-' + this.session.connection.connectionId + '-' + connectionId);
|
||||||
|
if (!!el) {
|
||||||
|
el.innerHTML = 'fiber_manual_record';
|
||||||
|
}
|
||||||
|
el = document.getElementById('pause-icon-' + this.session.connection.connectionId + '-' + connectionId);
|
||||||
|
if (!!el) {
|
||||||
|
el.innerHTML = 'pause';
|
||||||
|
}
|
||||||
|
el = document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connectionId);
|
||||||
|
if (!!el) {
|
||||||
|
el.style.display = 'none';
|
||||||
|
}
|
||||||
|
this.subscribers[connectionId].recording = false;
|
||||||
|
this.subscribers[connectionId].paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ export class TestApirestComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.paramsSubscription.unsubscribe();
|
if (!!this.paramsSubscription) { this.paramsSubscription.unsubscribe(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSessionId() {
|
private getSessionId() {
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
import { LocalRecorder } from 'openvidu-browser';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-local-recording-dialog',
|
||||||
|
template: `
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<div id="local-recorder-preview"></div>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button mat-dialog-close>Close</button>
|
||||||
|
<button mat-button (click)="recorder.download()">Download</button>
|
||||||
|
<button mat-button [disabled]="endpoint == ''" (click)="uploadFile()">Upload to</button>
|
||||||
|
<mat-form-field [style.font-size]="'14px'" [style.width]="'170px'">
|
||||||
|
<input matInput name="endpoint" [(ngModel)]="endpoint">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-icon *ngIf="uploading" [ngClass]="iconClass"
|
||||||
|
[style.margin-top]="'10px'" [style.color]="iconColor">{{uploadIcon}}</mat-icon>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
styles: [`
|
||||||
|
#quality-div {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
`],
|
||||||
|
})
|
||||||
|
export class LocalRecordingDialogComponent {
|
||||||
|
|
||||||
|
public myReference: MatDialogRef<LocalRecordingDialogComponent>;
|
||||||
|
|
||||||
|
private recorder: LocalRecorder;
|
||||||
|
|
||||||
|
private uploading = false;
|
||||||
|
private endpoint = '';
|
||||||
|
private uploadIcon: string;
|
||||||
|
private iconColor: string;
|
||||||
|
private iconClass = '';
|
||||||
|
|
||||||
|
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||||
|
this.recorder = data.recorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.myReference.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadFile() {
|
||||||
|
this.iconColor = 'black';
|
||||||
|
this.iconClass = 'rotating';
|
||||||
|
this.uploadIcon = 'cached';
|
||||||
|
this.uploading = true;
|
||||||
|
this.recorder.uploadAsBinary(this.endpoint)
|
||||||
|
.then(() => {
|
||||||
|
this.iconColor = 'green';
|
||||||
|
this.uploadIcon = 'done';
|
||||||
|
this.iconClass = '';
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
this.iconColor = 'red';
|
||||||
|
this.uploadIcon = 'clear';
|
||||||
|
this.iconClass = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MuteSubscribersService {
|
||||||
|
|
||||||
|
muted = false;
|
||||||
|
mutedEvent$ = new Subject<boolean>();
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
getMuted() {
|
||||||
|
return this.muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMuted(muted: boolean) {
|
||||||
|
this.muted = muted;
|
||||||
|
this.mutedEvent$.next(this.muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -66,7 +66,7 @@ button {
|
||||||
.video-container div.data-node .sub-btn {
|
.video-container div.data-node .sub-btn {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
border: none;
|
border: none;
|
||||||
background: white;
|
background: rgba(255, 255, 255, 0.75);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
|
@ -77,10 +77,26 @@ button {
|
||||||
color: #4d4d4d;
|
color: #4d4d4d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-container div.data-node .rec-btn {
|
||||||
|
float: right;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
color: #ac0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-container div.data-node .rec-btn:hover {
|
||||||
|
color: #ac000082;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-container div.data-node .rec-btn.publisher-rec-btn {
|
||||||
|
margin-top: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
.video-container div.data-node .material-icons {
|
.video-container div.data-node .material-icons {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 17px;
|
height: 17px;
|
||||||
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-expansion-panel-body {
|
.mat-expansion-panel-body {
|
||||||
|
@ -105,3 +121,62 @@ button {
|
||||||
.mat-expansion-panel-spacing {
|
.mat-expansion-panel-spacing {
|
||||||
margin: 3px 0 !important;
|
margin: 3px 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#local-recorder-preview video {
|
||||||
|
width: 500px;
|
||||||
|
height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Rotating animation*/
|
||||||
|
|
||||||
|
@-webkit-keyframes rotating
|
||||||
|
/* Safari and Chrome */
|
||||||
|
|
||||||
|
{
|
||||||
|
from {
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-o-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotating {
|
||||||
|
from {
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-o-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotating {
|
||||||
|
-webkit-animation: rotating 1s linear infinite;
|
||||||
|
-moz-animation: rotating 1s linear infinite;
|
||||||
|
-ms-animation: rotating 1s linear infinite;
|
||||||
|
-o-animation: rotating 1s linear infinite;
|
||||||
|
animation: rotating 1s linear infinite;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotating:hover {
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*End rotating animation*/
|
||||||
|
|
Loading…
Reference in New Issue