import { Component, Input, HostListener, ChangeDetectorRef, SimpleChanges, ElementRef, ViewChild, OnInit, OnDestroy, OnChanges } from '@angular/core'; import { Subscription } from 'rxjs/Subscription'; import { OpenVidu, Session, Subscriber, Publisher, Stream, Connection, LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent, SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent } from 'openvidu-browser'; import { OpenVidu as OpenViduAPI, Session as SessionAPI, SessionProperties as SessionPropertiesAPI, MediaMode, RecordingMode, RecordingLayout } from 'openvidu-node-client'; import { MatDialog, MatDialogRef } from '@angular/material'; 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 { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component'; import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component'; declare var $: any; export interface SessionConf { subscribeTo: boolean; publishTo: boolean; sendAudio: boolean; sendVideo: boolean; startSession: boolean; } export interface OpenViduEvent { name: string; content: string; } @Component({ selector: 'app-openvidu-instance', templateUrl: './openvidu-instance.component.html', styleUrls: ['./openvidu-instance.component.css'] }) export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { @Input() openviduUrl: string; @Input() openviduSecret: string; @Input() sessionConf: SessionConf; // Session join data clientData: string; sessionName: string; // Session options subscribeTo; publishTo; sendAudio; sendVideo; activeAudio = true; activeVideo = true; sendVideoRadio = true; subscribeToRemote = false; optionsVideo = 'video'; // Form 'check' and 'disable' attributes checkSubscribeTo = true; checkPublishTo = true; checkSendAudio = true; checkSendVideo = true; checkActiveAudio = true; checkActiveVideo = true; checkRadioVideo = true; checkRadioScreen = false; disablePublishTo = false; disableSendAudio = false; disableSendVideo = false; disableActiveAudio = false; disableActiveVideo = false; disableRadioButtons = false; // OpenVidu Browser objects OV: OpenVidu; session: Session; publisher: Publisher; subscribers = {}; // OpenVidu Node Client objects sessionProperties: SessionPropertiesAPI = { mediaMode: MediaMode.ROUTED, recordingMode: RecordingMode.MANUAL, defaultRecordingLayout: RecordingLayout.BEST_FIT, defaultCustomLayout: '', customSessionId: '' }; // Session audio and video status audioMuted = false; videoMuted = false; unpublished = false; publisherChanged = false; audioIcon = 'mic'; videoIcon = 'videocam'; publishIcon = 'stop'; sendAudioChange: boolean; sendVideoChange: boolean; events: OpenViduEvent[] = []; openviduError: any; private publisherRecorder: LocalRecorder; private publisherRecording = false; private publisherPaused = false; private muteSubscribersSubscription: Subscription; constructor( private changeDetector: ChangeDetectorRef, private dialog: MatDialog, private recordDialog: MatDialog, private testFeedService: TestFeedService, private muteSubscribersService: MuteSubscribersService, ) { this.generateSessionInfo(); } ngOnInit() { this.subscribeTo = this.sessionConf.subscribeTo; this.publishTo = this.sessionConf.publishTo; this.sendAudio = this.sessionConf.sendAudio; this.sendVideo = this.sessionConf.sendVideo; if (!this.publishTo) { this.publishTo = !this.publishTo; this.togglePublishTo(); } 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) { if (changes.openviduSecret) { this.openviduSecret = changes.openviduSecret.currentValue; } if (changes.openviduUrl) { this.openviduUrl = changes.openviduUrl.currentValue; } } ngOnDestroy() { if (!!this.muteSubscribersSubscription) { this.muteSubscribersSubscription.unsubscribe(); } this.leaveSession(); } @HostListener('window:beforeunload') beforeunloadHandler() { this.leaveSession(); } private generateSessionInfo(): void { this.sessionName = 'TestSession'; this.clientData = 'TestClient'; } private removeHttps = input => input.replace(/^https?:\/\//, ''); private joinSession(): void { if (this.session) { this.leaveSession(); } this.getToken().then(token => { this.joinSessionShared(token); }); } private joinSessionShared(token): void { this.OV = new OpenVidu(); this.session = this.OV.initSession(); this.addSessionEvents(this.session); 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(); } }) .catch(error => { console.log('There was an error connecting to the session:', error.code, error.message); }); } 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(); } private updateEventList(event: string, content: string) { this.events.push({ name: event, content: content }); this.testFeedService.pushNewEvent(this.sessionName, this.session.connection.connectionId, event, content); } toggleSubscribeTo(): void { this.subscribeTo = !this.subscribeTo; } togglePublishTo(): void { this.publishTo = !this.publishTo; this.sendAudio = this.publishTo; this.sendVideo = this.publishTo; this.activeAudio = this.publishTo; this.activeVideo = this.publishTo; this.checkPublishTo = this.publishTo; this.checkSendAudio = this.publishTo; this.checkSendVideo = this.publishTo; this.checkActiveAudio = this.publishTo; this.checkActiveVideo = this.publishTo; if (this.publishTo) { this.checkRadioVideo = true; this.optionsVideo = 'video'; } else { this.checkRadioVideo = false; this.optionsVideo = ''; } this.disableSendAudio = !this.publishTo; this.disableSendVideo = !this.publishTo; this.disableActiveAudio = !this.publishTo; this.disableActiveVideo = !this.publishTo; this.disableRadioButtons = !this.publishTo; this.subscribeToRemote = false; } toggleSendAudio(): void { this.sendAudio = !this.sendAudio; this.activeAudio = this.sendAudio; this.checkActiveAudio = this.sendAudio; this.disableActiveAudio = !this.sendAudio; if (!this.sendAudio && !this.sendVideo && this.publishTo) { this.togglePublishTo(); } } toggleSendVideo(): void { this.sendVideo = !this.sendVideo; this.activeVideo = this.sendVideo; this.checkActiveVideo = this.sendVideo; this.checkRadioScreen = false; if (this.sendVideo) { this.checkRadioVideo = true; this.optionsVideo = 'video'; } else { this.checkRadioVideo = false; this.optionsVideo = ''; } this.disableActiveVideo = !this.sendVideo; this.disableRadioButtons = !this.sendVideo; if (!this.sendAudio && !this.sendVideo && this.publishTo) { this.togglePublishTo(); } } toggleActiveAudio(): void { this.activeAudio = !this.activeAudio; } toggleActiveVideo(): void { this.activeVideo = !this.activeVideo; } sendMessage(): void { this.session.signal({ data: 'Test message', to: [], type: 'chat' }) .then(() => { console.log('Message succesfully sent'); }) .catch(error => { console.error(error); }); // 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; 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' }); } } }); 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); }); /*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'; } } this.subscribers[connectionId].recording = false; this.subscribers[connectionId].paused = false; if (!!this.subscribers[connectionId].recorder) { this.subscribers[connectionId].recorder.clean(); } } syncInitPublisher() { this.publisher = this.OV.initPublisher( 'local-vid-' + this.session.connection.connectionId, { 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 }, (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' }); } } }); this.addPublisherEvents(this.publisher); if (this.subscribeToRemote) { this.publisher.subscribeToRemote(); } this.session.publish(this.publisher); } asyncInitPublisher() { this.OV.initPublisherAsync( 'local-vid-' + this.session.connection.connectionId, { 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 }) .then(publisher => { this.publisher = publisher; this.addPublisherEvents(this.publisher); if (this.subscribeToRemote) { this.publisher.subscribeToRemote(); } this.session.publish(this.publisher) .then(() => { console.log(this.publisher); }) .catch(e => { console.error(e); }); }) .catch(err => { if (err) { console.error(err); this.openviduError = err; if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') { this.dialog.open(ExtensionDialogComponent, { data: { url: err.message }, disableClose: true, width: '250px' }); } } }); } 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'); } initGrayVideo(): void { this.OV.getUserMedia( { videoSource: undefined, resolution: '1280x720', frameRate: 10, } ) .then((mediaStream: MediaStream) => { const videoStreamTrack = mediaStream.getVideoTracks()[0]; const video = document.createElement('video'); video.srcObject = new MediaStream([videoStreamTrack]); video.play(); const canvas = document.createElement('canvas') as any; const ctx = canvas.getContext('2d'); ctx.filter = 'grayscale(100%)'; video.addEventListener('play', () => { const loop = () => { if (!video.paused && !video.ended) { ctx.drawImage(video, 0, 0, 300, 170); setTimeout(loop, 100); // Drawing at 10fps } }; loop(); }); const grayVideoTrack = canvas.captureStream(30).getVideoTracks()[0]; this.OV.initPublisher( document.body, { audioSource: false, videoSource: grayVideoTrack, insertMode: VideoInsertMode.APPEND }); }) .catch(error => { console.error(error); }); } openSessionPropertiesDialog() { this.sessionProperties.customSessionId = this.sessionName; const dialogRef = this.dialog.open(SessionPropertiesDialogComponent, { data: this.sessionProperties, width: '235px' }); dialogRef.afterClosed().subscribe((result: SessionPropertiesAPI) => { if (!!result) { this.sessionProperties = result; if (!!this.sessionProperties.customSessionId) { this.sessionName = this.sessionProperties.customSessionId; } } document.getElementById('session-settings-btn').classList.remove('cdk-program-focused'); }); } openSessionApiDialog() { const dialogRef = this.dialog.open(SessionApiDialogComponent, { data: { openVidu: new OpenViduAPI(this.openviduUrl, this.openviduSecret), sessionId: !!this.session ? this.session.sessionId : this.sessionName }, width: '280px' }); dialogRef.afterClosed().subscribe((result: string) => { document.getElementById('session-api-btn').classList.remove('cdk-program-focused'); }); } getToken(): Promise { const OV_NodeClient = new OpenViduAPI(this.openviduUrl, this.openviduSecret); if (!this.sessionProperties.customSessionId) { this.sessionProperties.customSessionId = this.sessionName; } return OV_NodeClient.createSession(this.sessionProperties) .then(session_NodeClient => { return session_NodeClient.generateToken(); }); } }