-
+
Video
@@ -71,6 +76,19 @@
to remote
+
+
+
+
+
+
+
@@ -85,21 +103,9 @@
{{sessionName}}
-
-
-
-
@@ -123,6 +129,10 @@
diff --git a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts
index 3e36ce5c..5ede01b0 100644
--- a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts
+++ b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts
@@ -7,7 +7,7 @@ import { Subscription } from 'rxjs/Subscription';
import {
OpenVidu, Session, Subscriber, Publisher, Stream, Connection,
LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent,
- SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent
+ SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent, PublisherSpeakingEvent, StreamManagerEvent, StreamManager
} from 'openvidu-browser';
import {
OpenVidu as OpenViduAPI,
@@ -22,10 +22,10 @@ import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component'
import { LocalRecordingDialogComponent } from '../dialogs/local-recording-dialog.component';
import { TestFeedService } from '../../services/test-feed.service';
import { MuteSubscribersService } from '../../services/mute-subscribers.service';
+import { EventsDialogComponent } from '../dialogs/events-dialog.component';
import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component';
import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component';
-declare var $: any;
export interface SessionConf {
subscribeTo: boolean;
@@ -56,6 +56,9 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
@Input()
sessionConf: SessionConf;
+ @Input()
+ index: number;
+
// Session join data
clientData: string;
sessionName: string;
@@ -91,7 +94,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
OV: OpenVidu;
session: Session;
publisher: Publisher;
- subscribers = {};
+ subscribers: Subscriber[] = [];
// OpenVidu Node Client objects
sessionProperties: SessionPropertiesAPI = {
@@ -102,17 +105,18 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
customSessionId: ''
};
- // Session audio and video status
- audioMuted = false;
- videoMuted = false;
- unpublished = false;
- publisherChanged = false;
- audioIcon = 'mic';
- videoIcon = 'videocam';
- publishIcon = 'stop';
-
- sendAudioChange: boolean;
- sendVideoChange: boolean;
+ sessionEvents = {
+ connectionCreated: true,
+ connectionDestroyed: true,
+ sessionDisconnected: true,
+ streamCreated: true,
+ streamDestroyed: true,
+ recordingStarted: true,
+ recordingStopped: true,
+ signal: true,
+ publisherStartSpeaking: false,
+ publisherStopSpeaking: false
+ };
events: OpenViduEvent[] = [];
@@ -127,8 +131,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
private changeDetector: ChangeDetectorRef,
private dialog: MatDialog,
private recordDialog: MatDialog,
- private testFeedService: TestFeedService,
- private muteSubscribersService: MuteSubscribersService,
+ private testFeedService: TestFeedService
) {
this.generateSessionInfo();
}
@@ -147,13 +150,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
if (this.sessionConf.startSession) {
this.joinSession();
}
-
- this.muteSubscribersSubscription = this.muteSubscribersService.mutedEvent$.subscribe(
- muteOrUnmute => {
- Object.keys(this.subscribers).forEach((key) => {
- this.subscribers[key].videoElement.muted = muteOrUnmute;
- });
- });
}
ngOnChanges(changes: SimpleChanges) {
@@ -166,7 +162,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
}
ngOnDestroy() {
- if (!!this.muteSubscribersSubscription) { this.muteSubscribersSubscription.unsubscribe(); }
this.leaveSession();
}
@@ -199,24 +194,24 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.session = this.OV.initSession();
- this.addSessionEvents(this.session);
+ this.updateSessionEvents({
+ connectionCreated: false,
+ connectionDestroyed: false,
+ sessionDisconnected: false,
+ streamCreated: false,
+ streamDestroyed: false,
+ recordingStarted: false,
+ recordingStopped: false,
+ signal: false,
+ publisherStartSpeaking: true,
+ publisherStopSpeaking: true
+ }, true);
this.session.connect(token, this.clientData)
.then(() => {
this.changeDetector.detectChanges();
if (this.publishTo) {
-
- this.audioMuted = !this.activeAudio;
- this.videoMuted = !this.activeVideo;
- this.unpublished = false;
- this.updateAudioIcon();
- this.updateVideoIcon();
- this.updatePublishIcon();
-
- this.sendAudioChange = this.sendAudio;
- this.sendVideoChange = this.sendVideo;
-
// this.asyncInitPublisher();
this.syncInitPublisher();
}
@@ -226,113 +221,14 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
});
}
-
private leaveSession(): void {
- if (!!this.publisherRecorder) {
- this.restartPublisherRecord();
- }
- Object.keys(this.subscribers).forEach((key) => {
- if (!!this.subscribers[key].recorder) {
- this.restartSubscriberRecord(key);
- }
- });
if (this.session) {
this.session.disconnect();
}
- this.session = null;
- this.OV = null;
- }
-
- private toggleAudio() {
- this.publisher.publishAudio(this.audioMuted);
- this.audioMuted = !this.audioMuted;
- this.updateAudioIcon();
- }
-
- private toggleVideo() {
- this.publisher.publishVideo(this.videoMuted);
- this.videoMuted = !this.videoMuted;
- this.updateVideoIcon();
- }
-
- private updateAudioIcon() {
- this.audioMuted ? this.audioIcon = 'mic_off' : this.audioIcon = 'mic';
- }
-
- private updateVideoIcon() {
- this.videoMuted ? this.videoIcon = 'videocam_off' : this.videoIcon = 'videocam';
- }
-
- private updatePublishIcon() {
- this.unpublished ? this.publishIcon = 'play_arrow' : this.publishIcon = 'stop';
- }
-
- private appendSubscriberData(videoElement: HTMLVideoElement, connection: Connection): void {
- const dataNode = document.createElement('div');
- dataNode.className = 'data-node';
- dataNode.id = 'data-' + this.session.connection.connectionId + '-' + connection.connectionId;
- dataNode.innerHTML = '
' + connection.data + '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
';
- videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
- document.getElementById('sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
- .addEventListener('click', this.subUnsubFromSubscriber.bind(this, connection.connectionId));
- document.getElementById('sub-video-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
- .addEventListener('click', this.subUnsubFromSubscriberVideo.bind(this, connection.connectionId));
- document.getElementById('sub-audio-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
- .addEventListener('click', this.subUnsubFromSubscriberAudio.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 =
- '
' +
- '
';
- 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 {
- $('#remote-vid-' + this.session.connection.connectionId)
- .find('#data-' + this.session.connection.connectionId + '-' + connectionId).remove();
+ delete this.session;
+ delete this.OV;
+ delete this.publisher;
+ this.subscribers = [];
}
private updateEventList(event: string, content: string) {
@@ -433,432 +329,122 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
// this.initGrayVideo();
}
- 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
;
- dialogRef = this.recordDialog.open(LocalRecordingDialogComponent, {
- disableClose: true,
- data: {
- recorder: this.publisherRecorder
- }
- });
- dialogRef.componentInstance.myReference = dialogRef;
+ updateSessionEvents(oldValues, firstTime) {
- dialogRef.afterOpen().subscribe(() => {
- this.afterOpenPreview(this.publisherRecorder);
- });
- dialogRef.afterClosed().subscribe(() => {
- this.afterClosePreview();
- });
- })
- .catch((error) => {
- console.error('Error stopping LocalRecorder: ' + error);
- });
- }
- }
-
- 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;
- 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(connectionId);
- });
- })
- .catch((error) => {
- console.error('Error stopping LocalRecorder: ' + error);
- });
- }
- }
-
- 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 {
- if (this.unpublished) {
- this.session.publish(this.publisher)
- .then(() => {
- console.log(this.publisher);
- })
- .catch(e => {
- console.error(e);
- });
- } else {
- this.session.unpublish(this.publisher);
- this.removeUserData(this.session.connection.connectionId);
- this.restartPublisherRecord();
- }
- this.unpublished = !this.unpublished;
- this.updatePublishIcon();
- }
-
- changePublisher() {
- let screenChange;
- if (!this.publisherChanged) {
- if (this.sendAudio && !this.sendVideo) {
- this.sendAudioChange = false;
- this.sendVideoChange = true;
- screenChange = false;
- } else if (!this.sendAudio && this.sendVideo) {
- this.sendAudioChange = true;
- this.sendVideoChange = false;
- } else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'video') {
- this.sendAudioChange = false;
- this.sendVideoChange = true;
- screenChange = true;
- } else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'screen') {
- this.sendAudioChange = false;
- this.sendVideoChange = true;
- screenChange = false;
- }
- } else {
- this.sendAudioChange = this.sendAudio;
- this.sendVideoChange = this.sendVideo;
- screenChange = this.optionsVideo === 'screen' ? true : false;
- }
-
- this.audioMuted = false;
- this.videoMuted = false;
- this.unpublished = false;
- this.updateAudioIcon();
- this.updateVideoIcon();
- this.updatePublishIcon();
-
- const otherPublisher = this.OV.initPublisher(
- 'local-vid-' + this.session.connection.connectionId,
- {
- audioSource: this.sendAudioChange ? undefined : false,
- videoSource: this.sendVideoChange ? (screenChange ? 'screen' : undefined) : false,
- publishAudio: (!this.publisherChanged) ? true : !this.audioMuted,
- publishVideo: (!this.publisherChanged) ? true : !this.videoMuted,
- resolution: '640x480',
- frameRate: 30,
- insertMode: VideoInsertMode.APPEND
- },
- (err) => {
- if (err) {
- console.warn(err);
- this.openviduError = err;
- if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
- this.dialog.open(ExtensionDialogComponent, {
- data: { url: err.message },
- disableClose: true,
- width: '250px'
- });
+ if (this.sessionEvents.streamCreated !== oldValues.streamCreated || firstTime) {
+ this.session.off('streamCreated');
+ if (this.sessionEvents.streamCreated) {
+ this.session.on('streamCreated', (event: StreamEvent) => {
+ this.changeDetector.detectChanges();
+ if (this.subscribeTo) {
+ this.syncSubscribe(this.session, event);
}
- }
- });
- this.addPublisherEvents(otherPublisher);
-
- otherPublisher.once('accessAllowed', () => {
- if (!this.unpublished) {
- this.session.unpublish(this.publisher);
- this.publisher = otherPublisher;
- this.removeUserData(this.session.connection.connectionId);
- this.restartPublisherRecord();
- }
- this.session.publish(otherPublisher);
- });
-
- this.publisherChanged = !this.publisherChanged;
- }
-
- subUnsubFromSubscriber(connectionId: string) {
- let subscriber: Subscriber = this.subscribers[connectionId].subscriber;
- if (this.subscribers[connectionId].subbed) {
- this.session.unsubscribe(subscriber);
- this.restartSubscriberRecord(connectionId);
- document.getElementById('data-' + this.session.connection.connectionId + '-' + connectionId).style.marginLeft = '0';
- document.getElementById('sub-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();
- document.getElementById('sub-video-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
- document.getElementById('sub-audio-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
- this.subscribers[connectionId].subbedVideo = false;
- this.subscribers[connectionId].subbedAudio = false;
- } else {
-
-
- this.session.subscribeAsync(subscriber.stream, 'remote-vid-' + this.session.connection.connectionId)
- .then(sub => {
- subscriber = sub;
- this.subscribers[connectionId].subscriber = subscriber;
- subscriber.on('videoElementCreated', (e: VideoElementEvent) => {
- if (!subscriber.stream.hasVideo) {
- $(e.element).css({ 'background-color': '#4d4d4d' });
- $(e.element).attr('poster', 'assets/images/volume.png');
- }
- this.subscribers[connectionId].videoElement = e.element;
- this.updateEventList('videoElementCreated', e.element.id);
- });
- subscriber.on('videoPlaying', (e: VideoElementEvent) => {
- this.removeUserData(connectionId);
- this.appendSubscriberData(e.element, subscriber.stream.connection);
- this.updateEventList('videoPlaying', e.element.id);
- });
- })
- .catch(err => {
- console.error(err);
+ this.updateEventList('streamCreated', event.stream.streamId);
});
-
-
- /*subscriber = this.session.subscribe(subscriber.stream, 'remote-vid-' + this.session.connection.connectionId);
- this.subscribers[connectionId].subscriber = subscriber;
- subscriber.on('videoElementCreated', (e) => {
- if (!subscriber.stream.hasVideo) {
- $(e.element).css({ 'background-color': '#4d4d4d' });
- $(e.element).attr('poster', 'assets/images/volume.png');
- }
- this.subscribers[connectionId].videoElement = e.element;
- this.updateEventList('videoElementCreated', e.element.id);
- });
- subscriber.on('videoPlaying', (e) => {
- this.removeUserData(connectionId);
- this.appendSubscriberData(e.element, subscriber.stream.connection);
- this.updateEventList('videoPlaying', e.element.id);
- });*/
-
-
- }
- this.subscribers[connectionId].subbed = !this.subscribers[connectionId].subbed;
- }
-
- subUnsubFromSubscriberVideo(connectionId: string) {
- this.subscribers[connectionId].subscriber.subscribeToVideo(!!this.subscribers[connectionId].subbedVideo);
- this.subscribers[connectionId].subbedVideo = !this.subscribers[connectionId].subbedVideo;
- document.getElementById('sub-video-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML =
- this.subscribers[connectionId].subbedVideo ? 'videocam_off' : 'videocam';
- }
-
- subUnsubFromSubscriberAudio(connectionId: string) {
- this.subscribers[connectionId].subscriber.subscribeToAudio(!!this.subscribers[connectionId].subbedAudio);
- this.subscribers[connectionId].subbedAudio = !this.subscribers[connectionId].subbedAudio;
- document.getElementById('sub-audio-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML =
- this.subscribers[connectionId].subbedAudio ? 'mic_off' : 'mic';
- }
-
- addSessionEvents(session: Session) {
- session.on('streamCreated', (event: StreamEvent) => {
-
- this.changeDetector.detectChanges();
-
- if (this.subscribeTo) {
- // this.syncSubscribe(session, event);
- this.asyncSubscribe(session, event);
- }
- this.updateEventList('streamCreated', event.stream.connection.connectionId);
- });
-
- session.on('streamDestroyed', (event: StreamEvent) => {
- this.removeUserData(event.stream.connection.connectionId);
- this.updateEventList('streamDestroyed', event.stream.connection.connectionId);
- });
- session.on('connectionCreated', (event: ConnectionEvent) => {
- this.updateEventList('connectionCreated', event.connection.connectionId);
- });
- session.on('connectionDestroyed', (event: ConnectionEvent) => {
- this.updateEventList('connectionDestroyed', event.connection.connectionId);
- });
- session.on('sessionDisconnected', (event: SessionDisconnectedEvent) => {
- this.updateEventList('sessionDisconnected', 'No data');
- if (event.reason === 'networkDisconnect') {
- this.session = null;
- this.OV = null;
- }
- });
- session.on('signal', (event: SignalEvent) => {
- this.updateEventList('signal', event.from.connectionId + '-' + event.data);
- });
-
- session.on('recordingStarted', (event: RecordingEvent) => {
- this.updateEventList('recordingStarted', event.id);
- });
-
- session.on('recordingStopped', (event: RecordingEvent) => {
- this.updateEventList('recordingStopped', event.id);
- });
-
- /*session.on('publisherStartSpeaking', (event) => {
- console.log('Publisher start speaking');
- });
-
- session.on('publisherStopSpeaking', (event) => {
- console.log('Publisher stop speaking');
- });*/
- }
-
- addPublisherEvents(publisher: Publisher) {
- publisher.on('videoElementCreated', (event: VideoElementEvent) => {
- if (this.publishTo &&
- (!this.sendVideoChange ||
- this.sendVideoChange &&
- !(this.optionsVideo !== 'screen') &&
- this.openviduError &&
- this.openviduError.name === 'NO_VIDEO_DEVICE')) {
- $(event.element).css({ 'background-color': '#4d4d4d' });
- $(event.element).attr('poster', 'assets/images/volume.png');
- }
- this.updateEventList('videoElementCreated', event.element.id);
- });
-
- publisher.on('accessAllowed', (e) => {
- this.updateEventList('accessAllowed', '');
- });
-
- publisher.on('accessDenied', (e) => {
- this.updateEventList('accessDenied', '');
- });
-
- publisher.on('accessDialogOpened', (e) => {
- this.updateEventList('accessDialogOpened', '');
- });
-
- publisher.on('accessDialogClosed', (e) => {
- this.updateEventList('accessDialogClosed', '');
- });
-
- publisher.on('videoPlaying', (e: VideoElementEvent) => {
- this.appendPublisherData(e.element);
- this.updateEventList('videoPlaying', e.element.id);
- });
-
- publisher.on('remoteVideoPlaying', (e: VideoElementEvent) => {
- this.appendPublisherData(e.element);
- this.updateEventList('remoteVideoPlaying', e.element.id);
- });
-
- publisher.on('streamCreated', (e: StreamEvent) => {
- this.updateEventList('streamCreated', e.stream.connection.connectionId);
- });
-
- publisher.on('streamDestroyed', (e: StreamEvent) => {
- this.updateEventList('streamDestroyed', e.stream.connection.connectionId);
- });
-
- publisher.on('videoElementDestroyed', (e: VideoElementEvent) => {
- this.updateEventList('videoElementDestroyed', '(Publisher)');
- });
- }
-
- private afterOpenPreview(recorder: LocalRecorder): void {
- this.muteSubscribersService.updateMuted(true);
- recorder.preview('recorder-preview').controls = true;
- }
-
- private afterClosePreview(connectionId?: string): void {
- this.muteSubscribersService.updateMuted(false);
- if (!!connectionId) {
- this.restartSubscriberRecord(connectionId);
- } else {
- this.restartPublisherRecord();
- }
- }
-
- private restartPublisherRecord(): void {
- if (!!this.session) {
- 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;
- if (!!this.publisherRecorder) {
- this.publisherRecorder.clean();
- }
- }
- private restartSubscriberRecord(connectionId: string): void {
- if (!!this.session) {
- 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';
+ if (this.sessionEvents.streamDestroyed !== oldValues.streamDestroyed || firstTime) {
+ this.session.off('streamDestroyed');
+ if (this.sessionEvents.streamDestroyed) {
+ this.session.on('streamDestroyed', (event: StreamEvent) => {
+ const index = this.subscribers.indexOf(event.stream.streamManager);
+ if (index > -1) {
+ this.subscribers.splice(index, 1);
+ }
+ this.updateEventList('streamDestroyed', event.stream.streamId);
+ });
}
}
- this.subscribers[connectionId].recording = false;
- this.subscribers[connectionId].paused = false;
- if (!!this.subscribers[connectionId].recorder) {
- this.subscribers[connectionId].recorder.clean();
+ if (this.sessionEvents.connectionCreated !== oldValues.connectionCreated || firstTime) {
+ this.session.off('connectionCreated');
+ if (this.sessionEvents.connectionCreated) {
+ this.session.on('connectionCreated', (event: ConnectionEvent) => {
+ this.updateEventList('connectionCreated', event.connection.connectionId);
+ });
+ }
+ }
+
+ if (this.sessionEvents.connectionDestroyed !== oldValues.connectionDestroyed || firstTime) {
+ this.session.off('connectionDestroyed');
+ if (this.sessionEvents.connectionDestroyed) {
+ this.session.on('connectionDestroyed', (event: ConnectionEvent) => {
+ delete this.subscribers[event.connection.connectionId];
+ this.updateEventList('connectionDestroyed', event.connection.connectionId);
+ });
+ }
+ }
+
+ if (this.sessionEvents.sessionDisconnected !== oldValues.sessionDisconnected || firstTime) {
+ this.session.off('sessionDisconnected');
+ if (this.sessionEvents.sessionDisconnected) {
+ this.session.on('sessionDisconnected', (event: SessionDisconnectedEvent) => {
+ this.updateEventList('sessionDisconnected', 'No data');
+ if (event.reason === 'networkDisconnect') {
+ this.session = null;
+ this.OV = null;
+ }
+ });
+ }
+ }
+
+ if (this.sessionEvents.signal !== oldValues.signal || firstTime) {
+ this.session.off('signal');
+ if (this.sessionEvents.signal) {
+ this.session.on('signal', (event: SignalEvent) => {
+ this.updateEventList('signal', event.from.connectionId + '-' + event.data);
+ });
+ }
+ }
+
+ if (this.sessionEvents.recordingStarted !== oldValues.recordingStarted || firstTime) {
+ this.session.off('recordingStarted');
+ if (this.sessionEvents.recordingStarted) {
+ this.session.on('recordingStarted', (event: RecordingEvent) => {
+ this.updateEventList('recordingStarted', event.id);
+ });
+ }
+ }
+
+ if (this.sessionEvents.recordingStopped !== oldValues.recordingStopped || firstTime) {
+ this.session.off('recordingStopped');
+ if (this.sessionEvents.recordingStopped) {
+ this.session.on('recordingStopped', (event: RecordingEvent) => {
+ this.updateEventList('recordingStopped', event.id);
+ });
+ }
+ }
+
+ if (this.sessionEvents.publisherStartSpeaking !== oldValues.publisherStartSpeaking || firstTime) {
+ this.session.off('publisherStartSpeaking');
+ if (this.sessionEvents.publisherStartSpeaking) {
+ this.session.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => {
+ this.updateEventList('publisherStartSpeaking', event.connection.connectionId);
+ });
+ }
+ }
+
+ if (this.sessionEvents.publisherStopSpeaking !== oldValues.publisherStopSpeaking || firstTime) {
+ this.session.off('publisherStopSpeaking');
+ if (this.sessionEvents.publisherStopSpeaking) {
+ this.session.on('publisherStopSpeaking', (event: PublisherSpeakingEvent) => {
+ this.updateEventList('publisherStopSpeaking', event.connection.connectionId);
+ });
+ }
}
}
syncInitPublisher() {
this.publisher = this.OV.initPublisher(
- 'local-vid-' + this.session.connection.connectionId,
+ undefined,
{
audioSource: this.sendAudio ? undefined : false,
videoSource: this.sendVideo ? (this.optionsVideo === 'screen' ? 'screen' : undefined) : false,
publishAudio: this.activeAudio,
publishVideo: this.activeVideo,
resolution: '640x480',
- frameRate: 30,
- insertMode: VideoInsertMode.APPEND
+ frameRate: 30
},
(err) => {
if (err) {
@@ -874,8 +460,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
}
});
- this.addPublisherEvents(this.publisher);
-
if (this.subscribeToRemote) {
this.publisher.subscribeToRemote();
}
@@ -897,7 +481,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
})
.then(publisher => {
this.publisher = publisher;
- this.addPublisherEvents(this.publisher);
if (this.subscribeToRemote) {
this.publisher.subscribeToRemote();
}
@@ -925,75 +508,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
}
syncSubscribe(session: Session, event) {
- 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: VideoElementEvent) => {
- if (!event.stream.hasVideo) {
- $(e.element).css({ 'background-color': '#4d4d4d' });
- $(e.element).attr('poster', 'assets/images/volume.png');
- }
- this.subscribers[subscriber.stream.connection.connectionId].videoElement = e.element;
- this.updateEventList('videoElementCreated', e.element.id);
- });
- subscriber.on('videoPlaying', (e: VideoElementEvent) => {
- this.appendSubscriberData(e.element, subscriber.stream.connection);
- this.updateEventList('videoPlaying', e.element.id);
- });
- subscriber.on('videoElementDestroyed', (e) => {
- this.updateEventList('videoElementDestroyed', '(Subscriber)');
- });
- }
-
- asyncSubscribe(session: Session, event) {
- session.subscribeAsync(event.stream, 'remote-vid-' + session.connection.connectionId)
- .then(subscriber => {
- this.subscribers[subscriber.stream.connection.connectionId] = {
- 'subscriber': subscriber,
- 'subbed': true,
- 'recorder': undefined,
- 'recording': false,
- 'paused': false,
- 'videoElement': undefined
- };
- subscriber.on('videoElementCreated', (e: VideoElementEvent) => {
- if (!event.stream.hasVideo) {
- $(e.element).css({ 'background-color': '#4d4d4d' });
- $(e.element).attr('poster', 'assets/images/volume.png');
- }
- this.subscribers[subscriber.stream.connection.connectionId].videoElement = e.element;
- this.updateEventList('videoElementCreated', e.element.id);
- });
- subscriber.on('videoPlaying', (e: VideoElementEvent) => {
- this.appendSubscriberData(e.element, subscriber.stream.connection);
- this.updateEventList('videoPlaying', e.element.id);
- });
- subscriber.on('videoElementDestroyed', (e) => {
- this.updateEventList('videoElementDestroyed', '(Subscriber)');
- });
- })
- .catch(err => {
- console.error(err);
- });
- }
-
- enableSpeakingEvents() {
- this.session.on('publisherStartSpeaking', (event) => {
- });
-
- this.session.on('publisherStopSpeaking', (event) => {
- });
- }
-
- disableSpeakingEvents() {
- this.session.off('publisherStartSpeaking');
- this.session.off('publisherStopSpeaking');
+ this.subscribers.push(session.subscribe(event.stream, undefined));
}
initGrayVideo(): void {
@@ -1050,7 +565,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.sessionName = this.sessionProperties.customSessionId;
}
}
- document.getElementById('session-settings-btn').classList.remove('cdk-program-focused');
+ document.getElementById('session-settings-btn-' + this.index).classList.remove('cdk-program-focused');
});
}
@@ -1064,7 +579,54 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
});
dialogRef.afterClosed().subscribe((result: string) => {
- document.getElementById('session-api-btn').classList.remove('cdk-program-focused');
+ document.getElementById('session-api-btn-' + this.index).classList.remove('cdk-program-focused');
+ });
+ }
+
+ openSessionEventsDialog() {
+
+ const oldValues = {
+ connectionCreated: this.sessionEvents.connectionCreated,
+ connectionDestroyed: this.sessionEvents.connectionDestroyed,
+ sessionDisconnected: this.sessionEvents.sessionDisconnected,
+ streamCreated: this.sessionEvents.streamCreated,
+ streamDestroyed: this.sessionEvents.streamDestroyed,
+ recordingStarted: this.sessionEvents.recordingStarted,
+ recordingStopped: this.sessionEvents.recordingStopped,
+ signal: this.sessionEvents.signal,
+ publisherStartSpeaking: this.sessionEvents.publisherStartSpeaking,
+ publisherStopSpeaking: this.sessionEvents.publisherStopSpeaking
+ };
+
+ const dialogRef = this.dialog.open(EventsDialogComponent, {
+ data: {
+ eventCollection: this.sessionEvents,
+ target: 'Session'
+ },
+ width: '280px',
+ autoFocus: false,
+ disableClose: true
+ });
+
+ dialogRef.afterClosed().subscribe((result) => {
+
+ if (!!this.session && JSON.stringify(this.sessionEvents) !== JSON.stringify(oldValues)) {
+ this.updateSessionEvents(oldValues, false);
+ }
+
+ this.sessionEvents = {
+ connectionCreated: result.connectionCreated,
+ connectionDestroyed: result.connectionDestroyed,
+ sessionDisconnected: result.sessionDisconnected,
+ streamCreated: result.streamCreated,
+ streamDestroyed: result.streamDestroyed,
+ recordingStarted: result.recordingStarted,
+ recordingStopped: result.recordingStopped,
+ signal: result.signal,
+ publisherStartSpeaking: result.publisherStartSpeaking,
+ publisherStopSpeaking: result.publisherStopSpeaking
+ };
+ document.getElementById('session-events-btn-' + this.index).classList.remove('cdk-program-focused');
});
}
@@ -1079,4 +641,15 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
});
}
+ udpateEventFromChild(event) {
+ this.updateEventList(event.event, event.content);
+ }
+
+ updateSubscriberFromChild(newSubscriber: Subscriber) {
+ const oldSubscriber = this.subscribers.filter(sub => {
+ return sub.stream.streamId === newSubscriber.stream.streamId;
+ })[0];
+ this.subscribers[this.subscribers.indexOf(oldSubscriber)] = newSubscriber;
+ }
+
}
diff --git a/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.html b/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.html
index 00ef80a9..f8eacfa5 100644
--- a/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.html
+++ b/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.html
@@ -16,7 +16,7 @@
diff --git a/openvidu-testapp/src/app/components/video/ov-video.component.ts b/openvidu-testapp/src/app/components/video/ov-video.component.ts
new file mode 100644
index 00000000..80b17a50
--- /dev/null
+++ b/openvidu-testapp/src/app/components/video/ov-video.component.ts
@@ -0,0 +1,28 @@
+import { Component, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
+import { StreamManager } from 'openvidu-browser';
+
+@Component({
+ selector: 'app-ov-video',
+ template: '
'
+})
+export class OpenViduVideoComponent implements AfterViewInit {
+
+ @ViewChild('videoElement') elementRef: ElementRef;
+
+ @Input() poster = '';
+
+ _streamManager: StreamManager;
+
+ ngAfterViewInit() {
+ this._streamManager.addVideoElement(this.elementRef.nativeElement);
+ }
+
+ @Input()
+ set streamManager(streamManager: StreamManager) {
+ this._streamManager = streamManager;
+ if (!!this.elementRef) {
+ this._streamManager.addVideoElement(this.elementRef.nativeElement);
+ }
+ }
+
+}
diff --git a/openvidu-testapp/src/app/components/video/video.component.css b/openvidu-testapp/src/app/components/video/video.component.css
new file mode 100644
index 00000000..0eed51fb
--- /dev/null
+++ b/openvidu-testapp/src/app/components/video/video.component.css
@@ -0,0 +1,98 @@
+app-ov-video {
+ float: left;
+ height: 90px;
+}
+
+.data-node {
+ width: 120px;
+ height: 90px;
+ float: left;
+ position: relative;
+ margin-left: -120px;
+ margin-top: 0;
+}
+
+p {
+ display: inline-flex;
+ vertical-align: top;
+ margin: 0;
+ background: #ffffff;
+ padding-left: 5px;
+ padding-right: 5px;
+ color: #797979;
+ font-weight: 100;
+ font-size: 14px;
+}
+
+.material-icons {
+ font-size: 17px;
+ width: 17px;
+ height: 17px;
+ line-height: 20px;
+}
+
+.video-btn {
+ border: none;
+ background: rgba(255, 255, 255, 0.75);
+ cursor: pointer;
+ padding: 0;
+ height: 20px;
+ float: left;
+}
+
+.video-btn:hover {
+ color: #4d4d4d;
+}
+
+.video-btn.top-row {
+ margin-top: 0;
+ display: inline-flex;
+ float: right;
+}
+
+.rec-btn {
+ float: right;
+ color: #ac0000;
+}
+
+.rec-btn:hover {
+ color: #ac000082;
+}
+
+.events-btn {
+ float: right;
+}
+
+.top-left-rounded {
+ border-top-left-radius: 2px;
+}
+
+.top-right-rounded {
+ border-top-right-radius: 2px;
+}
+
+.bottom-left-rounded {
+ border-bottom-left-radius: 2px;
+}
+
+.bottom-right-rounded {
+ border-bottom-right-radius: 2px;
+}
+
+.grey-background {
+ background-color: #4d4d4d
+}
+
+.top-div {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 100%;
+}
+
+.bottom-div {
+ position: absolute;
+ bottom: 0;
+ height: 20px;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/openvidu-testapp/src/app/components/video/video.component.html b/openvidu-testapp/src/app/components/video/video.component.html
new file mode 100644
index 00000000..60d07f11
--- /dev/null
+++ b/openvidu-testapp/src/app/components/video/video.component.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{streamManager.stream.connection.data}}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/openvidu-testapp/src/app/components/video/video.component.ts b/openvidu-testapp/src/app/components/video/video.component.ts
new file mode 100644
index 00000000..c0056ab9
--- /dev/null
+++ b/openvidu-testapp/src/app/components/video/video.component.ts
@@ -0,0 +1,569 @@
+import { Component, Input, OnInit, ViewChild, ElementRef, Output, EventEmitter, OnDestroy } from '@angular/core';
+import { MatDialog, MatDialogRef } from '@angular/material';
+
+import {
+ StreamManager,
+ StreamManagerEvent,
+ VideoElementEvent,
+ Subscriber,
+ Session,
+ LocalRecorder,
+ OpenVidu,
+ Publisher,
+ StreamEvent,
+ VideoInsertMode
+} from 'openvidu-browser';
+
+import { EventsDialogComponent } from '../dialogs/events-dialog.component';
+import { MuteSubscribersService } from '../../services/mute-subscribers.service';
+import { Subscription } from 'rxjs/Subscription';
+import { LocalRecordingDialogComponent } from '../dialogs/local-recording-dialog.component';
+import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component';
+import { OpenViduVideoComponent } from './ov-video.component';
+
+@Component({
+ selector: 'app-video',
+ templateUrl: './video.component.html',
+ styleUrls: ['./video.component.css']
+})
+export class VideoComponent implements OnInit, OnDestroy {
+
+ @Input() streamManager: StreamManager;
+ @Input() OV: OpenVidu;
+ @Input() eventCollection: any;
+
+ @Output() updateEventListInParent = new EventEmitter();
+ @Output() reSubbed = new EventEmitter();
+
+ subbed = true;
+ subbedVideo = true;
+ subbedAudio = true;
+ recorder = undefined;
+ recording = false;
+ recordingPaused = false;
+ videoElement = undefined;
+ showButtons = false;
+ videoClasses = '';
+ videoPoster = '';
+
+ unpublished = false;
+ publisherChanged = false;
+ audioMuted = false;
+ videoMuted = false;
+ sendAudio = true;
+ sendVideo = true;
+ sendAudioChange = false;
+ sendVideoChange = false;
+ optionsVideo = '';
+
+ private muteSubscribersSubscription: Subscription;
+
+ // Icons
+ pubSubIcon = 'stop';
+ pubSubVideoIcon = 'videocam';
+ pubSubAudioIcon = 'mic';
+ recordIcon = 'fiber_manual_record';
+ pauseRecordIcon = '';
+
+ constructor(private dialog: MatDialog, private muteSubscribersService: MuteSubscribersService
+ ) { }
+
+ ngOnInit() {
+
+ if (this.streamManager.remote) {
+ // Init subscriber events
+ this.eventCollection = {
+ videoElementCreated: true,
+ videoElementDestroyed: true,
+ streamPlaying: true
+ };
+ this.updateSubscriberEvents({
+ videoElementCreated: false,
+ videoElementDestroyed: false,
+ streamPlaying: false
+ });
+
+ } else {
+ // Init publisher events
+ this.eventCollection = {
+ videoElementCreated: true,
+ videoElementDestroyed: true,
+ streamPlaying: true,
+ accessAllowed: true,
+ accessDenied: true,
+ accessDialogOpened: true,
+ accessDialogClosed: true,
+ streamCreated: true,
+ streamDestroyed: true
+ };
+ this.updatePublisherEvents(
+
this.streamManager,
+ {
+ videoElementCreated: false,
+ videoElementDestroyed: false,
+ streamPlaying: false,
+ accessAllowed: false,
+ accessDenied: false,
+ accessDialogOpened: false,
+ accessDialogClosed: false,
+ streamCreated: false,
+ streamDestroyed: false
+ });
+ this.sendAudio = this.streamManager.stream.hasAudio;
+ this.sendVideo = this.streamManager.stream.hasVideo;
+ this.optionsVideo = this.streamManager.stream.typeOfVideo;
+ }
+
+ this.muteSubscribersSubscription = this.muteSubscribersService.mutedEvent$.subscribe(muteOrUnmute => {
+ this.streamManager.videos.forEach(v => {
+ v.video.muted = muteOrUnmute;
+ });
+ });
+ }
+
+ ngOnDestroy() {
+ if (!!this.recorder) {
+ this.recorder.clean();
+ }
+ if (!!this.muteSubscribersSubscription) { this.muteSubscribersSubscription.unsubscribe(); }
+ }
+
+ subUnsub() {
+ const subscriber: Subscriber = this.streamManager;
+ if (this.subbed) {
+ this.streamManager.stream.session.unsubscribe(subscriber);
+ this.restartRecorder();
+
+ this.pubSubVideoIcon = '';
+ this.pubSubAudioIcon = '';
+ this.recordIcon = '';
+ this.pauseRecordIcon = '';
+ this.pubSubIcon = 'play_arrow';
+ this.subbedVideo = false;
+ this.subbedAudio = false;
+ } else {
+ const oldValues = {
+ videoElementCreated: this.eventCollection.videoElementCreated,
+ videoElementDestroyed: this.eventCollection.videoElementDestroyed,
+ streamPlaying: this.eventCollection.streamPlaying
+ };
+ this.streamManager = this.streamManager.stream.session.subscribe(subscriber.stream, undefined);
+ this.reSubbed.emit(this.streamManager);
+
+ this.pubSubVideoIcon = 'videocam';
+ this.pubSubAudioIcon = 'mic';
+ this.recordIcon = 'fiber_manual_record';
+ this.pauseRecordIcon = '';
+ this.pubSubIcon = 'stop';
+ this.subbedVideo = true;
+ this.subbedAudio = true;
+
+ this.updateSubscriberEvents(oldValues);
+ }
+ this.subbed = !this.subbed;
+ }
+
+ subUnsubVideo(connectionId: string) {
+ const subscriber: Subscriber = this.streamManager;
+ this.subbedVideo = !this.subbedVideo;
+ subscriber.subscribeToVideo(this.subbedVideo);
+ this.pubSubVideoIcon = this.subbedVideo ? 'videocam' : 'videocam_off';
+ }
+
+ subUnsubAudio(connectionId: string) {
+ const subscriber: Subscriber = this.streamManager;
+ this.subbedAudio = !this.subbedAudio;
+ subscriber.subscribeToAudio(this.subbedAudio);
+ this.pubSubAudioIcon = this.subbedAudio ? 'mic' : 'mic_off';
+ }
+
+ pubUnpub() {
+ const publisher: Publisher = this.streamManager;
+ if (this.unpublished) {
+ this.streamManager.stream.session.publish(publisher)
+ .then(() => {
+ console.log(publisher);
+ })
+ .catch(e => {
+ console.error(e);
+ });
+ } else {
+ this.streamManager.stream.session.unpublish(publisher);
+ }
+ this.unpublished = !this.unpublished;
+ this.unpublished ? this.pubSubIcon = 'play_arrow' : this.pubSubIcon = 'stop';
+ }
+
+ pubUnpubVideo() {
+ const publisher: Publisher = this.streamManager;
+ publisher.publishVideo(this.videoMuted);
+ this.videoMuted = !this.videoMuted;
+ this.pubSubVideoIcon = this.videoMuted ? 'videocam_off' : 'videocam';
+ }
+
+ pubUnpubAudio() {
+ const publisher: Publisher = this.streamManager;
+ publisher.publishAudio(this.audioMuted);
+ this.audioMuted = !this.audioMuted;
+ this.pubSubAudioIcon = this.audioMuted ? 'mic_off' : 'mic';
+ }
+
+ changePub() {
+ let screenChange;
+ if (!this.publisherChanged) {
+ if (this.sendAudio && !this.sendVideo) {
+ this.sendAudioChange = false;
+ this.sendVideoChange = true;
+ screenChange = false;
+ } else if (!this.sendAudio && this.sendVideo) {
+ this.sendAudioChange = true;
+ this.sendVideoChange = false;
+ } else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'CAMERA') {
+ this.sendAudioChange = false;
+ this.sendVideoChange = true;
+ screenChange = true;
+ } else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'SCREEN') {
+ this.sendAudioChange = false;
+ this.sendVideoChange = true;
+ screenChange = false;
+ }
+ } else {
+ this.sendAudioChange = this.sendAudio;
+ this.sendVideoChange = this.sendVideo;
+ screenChange = this.optionsVideo === 'SCREEN' ? true : false;
+ }
+
+ this.audioMuted = false;
+ this.videoMuted = false;
+ this.unpublished = false;
+
+ const otherPublisher = this.OV.initPublisher(
+ undefined,
+ {
+ audioSource: this.sendAudioChange ? undefined : false,
+ videoSource: this.sendVideoChange ? (screenChange ? 'screen' : undefined) : false,
+ publishAudio: (!this.publisherChanged) ? true : !this.audioMuted,
+ publishVideo: (!this.publisherChanged) ? true : !this.videoMuted,
+ resolution: '640x480',
+ frameRate: 30,
+ insertMode: VideoInsertMode.APPEND
+ },
+ (err) => {
+ if (err) {
+ console.warn(err);
+ if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
+ this.dialog.open(ExtensionDialogComponent, {
+ data: { url: err.message },
+ disableClose: true,
+ width: '250px'
+ });
+ }
+ }
+ });
+ this.updatePublisherEvents(otherPublisher, {
+ videoElementCreated: !this.eventCollection.videoElementCreated,
+ videoElementDestroyed: !this.eventCollection.videoElementDestroyed,
+ streamPlaying: !this.eventCollection.streamPlaying,
+ accessAllowed: !this.eventCollection.accessAllowed,
+ accessDenied: !this.eventCollection.accessDenied,
+ accessDialogOpened: !this.eventCollection.accessDialogOpened,
+ accessDialogClosed: !this.eventCollection.accessDialogClosed,
+ streamCreated: !this.eventCollection.streamCreated,
+ streamDestroyed: !this.eventCollection.streamDestroyed
+ });
+
+ otherPublisher.once('accessAllowed', () => {
+ if (!this.unpublished) {
+ this.streamManager.stream.session.unpublish(this.streamManager);
+ this.streamManager = otherPublisher;
+ }
+ this.streamManager.stream.session.publish(otherPublisher).then(() => {
+ console.log(this.streamManager);
+ });
+ });
+
+ this.publisherChanged = !this.publisherChanged;
+ }
+
+ updateSubscriberEvents(oldValues) {
+ const sub: Subscriber = this.streamManager;
+
+ if (this.eventCollection.videoElementCreated) {
+ if (!oldValues.videoElementCreated) {
+ sub.on('videoElementCreated', (event: VideoElementEvent) => {
+ if (!sub.stream.hasVideo) {
+ this.videoClasses = 'grey-background';
+ this.videoPoster = 'assets/images/volume.png';
+ } else {
+ this.videoClasses = '';
+ this.videoPoster = '';
+ }
+ this.updateEventListInParent.emit({
+ event: 'videoElementCreated',
+ content: event.element.id
+ });
+ });
+ }
+ } else {
+ sub.off('videoElementCreated');
+ }
+
+ if (this.eventCollection.videoElementDestroyed) {
+ if (!oldValues.videoElementDestroyed) {
+ sub.on('videoElementDestroyed', (event: VideoElementEvent) => {
+ this.showButtons = false;
+ this.updateEventListInParent.emit({
+ event: 'videoElementDestroyed',
+ content: event.element.id
+ });
+ });
+ }
+ } else {
+ sub.off('videoElementDestroyed');
+ }
+
+ if (this.eventCollection.streamPlaying) {
+ if (!oldValues.streamPlaying) {
+ sub.on('streamPlaying', (event: StreamManagerEvent) => {
+ this.showButtons = true;
+ this.updateEventListInParent.emit({
+ event: 'streamPlaying',
+ content: this.streamManager.stream.streamId
+ });
+ });
+ }
+ } else {
+ sub.off('streamPlaying');
+ }
+ }
+
+ updatePublisherEvents(pub: Publisher, oldValues: any) {
+ if (this.eventCollection.videoElementCreated) {
+ if (!oldValues.videoElementCreated) {
+ pub.on('videoElementCreated', (event: VideoElementEvent) => {
+ if (!pub.stream.hasVideo) {
+ this.videoClasses = 'grey-background';
+ this.videoPoster = 'assets/images/volume.png';
+ } else {
+ this.videoClasses = '';
+ this.videoPoster = '';
+ }
+ this.updateEventListInParent.emit({
+ event: 'videoElementCreated',
+ content: event.element.id
+ });
+ });
+ }
+ } else {
+ pub.off('videoElementCreated');
+ }
+
+ if (this.eventCollection.accessAllowed) {
+ if (!oldValues.accessAllowed) {
+ pub.on('accessAllowed', (e) => {
+ this.updateEventListInParent.emit({
+ event: 'accessAllowed',
+ content: ''
+ });
+ });
+ }
+ } else {
+ pub.off('accessAllowed');
+ }
+
+ if (this.eventCollection.accessDenied) {
+ if (!oldValues.accessDenied) {
+ pub.on('accessDenied', (e) => {
+ this.updateEventListInParent.emit({
+ event: 'accessDenied',
+ content: ''
+ });
+ });
+ }
+ } else {
+ pub.off('accessDenied');
+ }
+
+ if (this.eventCollection.accessDialogOpened) {
+ if (!oldValues.accessDialogOpened) {
+ pub.on('accessDialogOpened', (e) => {
+ this.updateEventListInParent.emit({
+ event: 'accessDialogOpened',
+ content: ''
+ });
+ });
+ }
+ } else {
+ pub.off('accessDialogOpened');
+ }
+
+ if (this.eventCollection.accessDialogClosed) {
+ if (!oldValues.accessDialogClosed) {
+ pub.on('accessDialogClosed', (e) => {
+ this.updateEventListInParent.emit({
+ event: 'accessDialogClosed',
+ content: ''
+ });
+ });
+ }
+ } else {
+ pub.off('accessDialogClosed');
+ }
+
+ if (this.eventCollection.streamCreated) {
+ if (!oldValues.streamCreated) {
+ pub.on('streamCreated', (e: StreamEvent) => {
+ this.updateEventListInParent.emit({
+ event: 'streamCreated',
+ content: e.stream.streamId
+ });
+ });
+ }
+ } else {
+ pub.off('streamCreated');
+ }
+
+ if (this.eventCollection.streamDestroyed) {
+ if (!oldValues.streamDestroyed) {
+ pub.on('streamDestroyed', (e: StreamEvent) => {
+ this.updateEventListInParent.emit({
+ event: 'streamDestroyed',
+ content: e.stream.streamId
+ });
+ });
+ }
+ } else {
+ pub.off('streamDestroyed');
+ }
+
+ if (this.eventCollection.videoElementDestroyed) {
+ if (!oldValues.videoElementDestroyed) {
+ pub.on('videoElementDestroyed', (e: VideoElementEvent) => {
+ this.updateEventListInParent.emit({
+ event: 'videoElementDestroyed',
+ content: '(Publisher)'
+ });
+ });
+ }
+ } else {
+ pub.off('videoElementDestroyed');
+ }
+
+ if (this.eventCollection.streamPlaying) {
+ if (!oldValues.streamPlaying) {
+ pub.on('streamPlaying', (event: StreamManagerEvent) => {
+ this.showButtons = true;
+ this.updateEventListInParent.emit({
+ event: 'streamPlaying',
+ content: this.streamManager.stream.streamId
+ });
+ });
+ }
+ } else {
+ pub.off('streamPlaying');
+ }
+ }
+
+ openSubscriberEventsDialog() {
+ const oldValues = {
+ videoElementCreated: this.eventCollection.videoElementCreated,
+ videoElementDestroyed: this.eventCollection.videoElementDestroyed,
+ streamPlaying: this.eventCollection.streamPlaying
+ };
+ const dialogRef = this.dialog.open(EventsDialogComponent, {
+ data: {
+ eventCollection: this.eventCollection,
+ target: 'Subscriber'
+ },
+ width: '280px',
+ autoFocus: false,
+ disableClose: true
+ });
+ dialogRef.afterClosed().subscribe((result) => {
+ this.updateSubscriberEvents(oldValues);
+ });
+ }
+
+
+ openPublisherEventsDialog() {
+ const oldValues = {
+ videoElementCreated: this.eventCollection.videoElementCreated,
+ videoElementDestroyed: this.eventCollection.videoElementDestroyed,
+ streamPlaying: this.eventCollection.streamPlaying,
+ accessAllowed: this.eventCollection.accessAllowed,
+ accessDenied: this.eventCollection.accessDenied,
+ accessDialogOpened: this.eventCollection.accessDialogOpened,
+ accessDialogClosed: this.eventCollection.accessDialogClosed,
+ streamCreated: this.eventCollection.streamCreated,
+ streamDestroyed: this.eventCollection.streamDestroyed
+ };
+ const dialogRef = this.dialog.open(EventsDialogComponent, {
+ data: {
+ eventCollection: this.eventCollection,
+ target: 'Publisher'
+ },
+ width: '280px',
+ autoFocus: false,
+ disableClose: true
+ });
+ dialogRef.afterClosed().subscribe((result) => {
+ this.updatePublisherEvents(this.streamManager, oldValues);
+ });
+ }
+
+ record(): void {
+ if (!this.recording) {
+ this.recorder = this.OV.initLocalRecorder(this.streamManager.stream);
+ this.recorder.record();
+ this.recording = true;
+ this.recordIcon = 'stop';
+ this.pauseRecordIcon = 'pause';
+ } else {
+ this.recorder.stop()
+ .then(() => {
+ let dialogRef: MatDialogRef;
+ dialogRef = this.dialog.open(LocalRecordingDialogComponent, {
+ disableClose: true,
+ data: {
+ recorder: this.recorder
+ }
+ });
+ dialogRef.componentInstance.myReference = dialogRef;
+
+ dialogRef.afterOpen().subscribe(() => {
+ this.muteSubscribersService.updateMuted(true);
+ this.recorder.preview('recorder-preview').controls = true;
+ });
+ dialogRef.afterClosed().subscribe(() => {
+ this.muteSubscribersService.updateMuted(false);
+ this.restartRecorder();
+ });
+ })
+ .catch((error) => {
+ console.error('Error stopping LocalRecorder: ' + error);
+ });
+ }
+ }
+
+ pauseRecord(): void {
+ if (!this.recordingPaused) {
+ this.recorder.pause();
+ this.pauseRecordIcon = 'play_arrow';
+ } else {
+ this.recorder.resume();
+ this.pauseRecordIcon = 'pause';
+ }
+ this.recordingPaused = !this.recordingPaused;
+ }
+
+ private restartRecorder() {
+ this.recording = false;
+ this.recordingPaused = false;
+ this.recordIcon = 'fiber_manual_record';
+ this.pauseRecordIcon = '';
+ if (!!this.recorder) {
+ this.recorder.clean();
+ }
+ }
+
+}
diff --git a/openvidu-testapp/src/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 b/openvidu-testapp/src/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2
new file mode 100644
index 00000000..af37c6a9
Binary files /dev/null and b/openvidu-testapp/src/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 differ
diff --git a/openvidu-testapp/src/index.html b/openvidu-testapp/src/index.html
index 27abaf4d..4bb6d2cc 100644
--- a/openvidu-testapp/src/index.html
+++ b/openvidu-testapp/src/index.html
@@ -9,11 +9,6 @@
-
-
-
-
diff --git a/openvidu-testapp/src/material-icons.css b/openvidu-testapp/src/material-icons.css
new file mode 100644
index 00000000..8cbb0e3d
--- /dev/null
+++ b/openvidu-testapp/src/material-icons.css
@@ -0,0 +1,23 @@
+/* fallback */
+@font-face {
+ font-family: 'Material Icons';
+ font-style: normal;
+ font-weight: 400;
+ src: url(/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
+ }
+
+ .material-icons {
+ font-family: 'Material Icons';
+ font-weight: normal;
+ font-style: normal;
+ font-size: 24px;
+ line-height: 1;
+ letter-spacing: normal;
+ text-transform: none;
+ display: inline-block;
+ white-space: nowrap;
+ word-wrap: normal;
+ direction: ltr;
+ -webkit-font-feature-settings: 'liga';
+ -webkit-font-smoothing: antialiased;
+ }
\ No newline at end of file
diff --git a/openvidu-testapp/src/styles.css b/openvidu-testapp/src/styles.css
index 74c44f00..46f772ae 100644
--- a/openvidu-testapp/src/styles.css
+++ b/openvidu-testapp/src/styles.css
@@ -38,67 +38,6 @@ button {
line-height: 15px !important;
}
-.video-container video {
- float: left;
-}
-
-.video-container div.data-node {
- width: 120px;
- height: 90px;
- float: left;
- position: relative;
- margin-left: -120px;
- margin-top: 0;
-}
-
-.video-container p {
- margin-top: 0;
- width: fit-content;
- background: #ffffff;
- padding-left: 5px;
- padding-right: 5px;
- color: #797979;
- font-weight: 100;
- font-size: 14px;
- border-bottom-right-radius: 2px;
-}
-
-.video-container div.data-node .sub-btn {
- outline: 0;
- border: none;
- background: rgba(255, 255, 255, 0.75);
- cursor: pointer;
- padding: 0;
- margin-top: 40px;
- border-top-right-radius: 2px;
-}
-
-.video-container div.data-node .sub-btn:hover {
- 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 {
- font-size: 17px;
- width: 17px;
- height: 17px;
- line-height: 20px;
-}
-
.mat-expansion-panel-body {
font-size: 9.5px !important;
padding: 0 9px 0px !important;