From 638d548b9f1915ee1347f04fd77d03c5ca5a8371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Sun, 4 Mar 2018 13:21:43 +0100 Subject: [PATCH] Updated RoomClient to support screen sharing. --- app/lib/RoomClient.js | 202 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 200 insertions(+), 2 deletions(-) diff --git a/app/lib/RoomClient.js b/app/lib/RoomClient.js index c9ebcf7..ab5b7a4 100644 --- a/app/lib/RoomClient.js +++ b/app/lib/RoomClient.js @@ -1,10 +1,12 @@ import protooClient from 'protoo-client'; import * as mediasoupClient from 'mediasoup-client'; import Logger from './Logger'; +import ScreenShare from './ScreenShare'; import { getProtooUrl } from './urlFactory'; import * as cookiesManager from './cookiesManager'; import * as requestActions from './redux/requestActions'; import * as stateActions from './redux/stateActions'; +import { getBrowserType } from './utils'; const logger = new Logger('RoomClient'); @@ -85,6 +87,10 @@ export default class RoomClient resolution : 'hd' }; + this._screenSharing = ScreenShare.create(); + + this._screenSharingProducer = null; + this._join({ displayName, device }); } @@ -189,6 +195,63 @@ export default class RoomClient this._micProducer.resume(); } + enableScreenSharing() + { + logger.debug('enableScreenSharing()'); + + this._dispatch( + stateActions.setScreenShareInProgress(true)); + + return Promise.resolve() + .then(() => + { + const browser = getBrowserType(); + + switch (browser) + { + case 'chrome': + { + // Check if we have extension, if not, try to install + // if (!('__multipartyMeetingScreenShareExtensionAvailable__' in window)) + // { + // window.addEventListener('message', function(ev) + // { + // if (ev.data.type === 'ScreenShareInjected') + // { + // } + // }, false); + // } + break; + } + case 'firefox': + { + break; + } + default: + { + return Promise.reject( + new Error('Unsupported browser for screen sharing')); + } + } + }) + .then(() => + { + return this._setScreenShareProducer(); + }) + .then(() => + { + this._dispatch( + stateActions.setScreenShareInProgress(false)); + }) + .catch((error) => + { + logger.error('enableScreenSharing() | failed: %o', error); + + this._dispatch( + stateActions.setScreenShareInProgress(false)); + }); + } + enableWebcam() { logger.debug('enableWebcam()'); @@ -222,6 +285,30 @@ export default class RoomClient }); } + disableScreenSharing() + { + logger.debug('disableScreenSharing()'); + + this._dispatch( + stateActions.setScreenShareInProgress(true)); + + return Promise.resolve() + .then(() => + { + this._screenSharingProducer.close(); + + this._dispatch( + stateActions.setScreenShareInProgress(false)); + }) + .catch((error) => + { + logger.error('disableScreenSharing() | failed: %o', error); + + this._dispatch( + stateActions.setScreenShareInProgress(false)); + }); + } + disableWebcam() { logger.debug('disableWebcam()'); @@ -733,8 +820,9 @@ export default class RoomClient // Set our media capabilities. this._dispatch(stateActions.setMediaCapabilities( { - canSendMic : this._room.canSend('audio'), - canSendWebcam : this._room.canSend('video') + canSendMic : this._room.canSend('audio'), + canSendWebcam : this._room.canSend('video'), + canShareScreen : this._room.canSend('video') })); }) .then(() => @@ -906,6 +994,116 @@ export default class RoomClient }); } + _setScreenShareProducer() + { + if (!this._room.canSend('video')) + { + return Promise.reject( + new Error('cannot send screen')); + } + + let producer; + + return Promise.resolve() + .then(() => + { + const available = this._screenSharing.isScreenShareAvailable(); + + if (!available) + throw new Error('screen sharing not available'); + + logger.debug('_setScreenShareProducer() | calling getUserMedia()'); + + return this._screenSharing.start({ + width : 1280, + height : 720, + frameRate : 3 + }); + }) + .then((stream) => + { + const track = stream.getVideoTracks()[0]; + + producer = this._room.createProducer( + track, { simulcast: false }, { source: 'screen' }); + + // No need to keep original track. + track.stop(); + + // Send it. + return producer.send(this._sendTransport); + }) + .then(() => + { + this._screenSharingProducer = producer; + + this._dispatch(stateActions.addProducer( + { + id : producer.id, + source : 'screen', + deviceLabel : 'screen', + type : 'screen', + locallyPaused : producer.locallyPaused, + remotelyPaused : producer.remotelyPaused, + track : producer.track, + codec : producer.rtpParameters.codecs[0].name + })); + + producer.on('close', (originator) => + { + logger.debug( + 'webcam Producer "close" event [originator:%s]', originator); + + this._screenSharingProducer = null; + this._dispatch(stateActions.removeProducer(producer.id)); + }); + + producer.on('pause', (originator) => + { + logger.debug( + 'webcam Producer "pause" event [originator:%s]', originator); + + this._dispatch(stateActions.setProducerPaused(producer.id, originator)); + }); + + producer.on('resume', (originator) => + { + logger.debug( + 'webcam Producer "resume" event [originator:%s]', originator); + + this._dispatch(stateActions.setProducerResumed(producer.id, originator)); + }); + + producer.on('handled', () => + { + logger.debug('webcam Producer "handled" event'); + }); + + producer.on('unhandled', () => + { + logger.debug('webcam Producer "unhandled" event'); + }); + }) + .then(() => + { + logger.debug('_setScreenShareProducer() succeeded'); + }) + .catch((error) => + { + logger.error('_setScreenShareProducer() failed:%o', error); + + this._dispatch(requestActions.notify( + { + text : `Screen share producer failed: ${error.name}:${error.message}` + })); + + if (producer) + producer.close(); + + throw error; + }); + } + _setWebcamProducer() { if (!this._room.canSend('video'))