diff --git a/app.js b/app.js index 0223165b2..c64cfeff9 100644 --- a/app.js +++ b/app.js @@ -62,8 +62,6 @@ const APP = { conference, API, init () { - this.desktopsharing = - require("./modules/desktopsharing/desktopsharing"); this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut"); this.translation = require("./modules/translation/translation"); @@ -75,10 +73,6 @@ function init() { var isUIReady = APP.UI.start(); if (isUIReady) { APP.conference.init({roomName: buildRoomName()}).then(function () { - // init desktop before UI, in order to make sure - // autoEnableDesktopSharing works - APP.desktopsharing.init(JitsiMeetJS.isDesktopSharingEnabled()); - APP.UI.initConference(); APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) { diff --git a/conference.js b/conference.js index 77eae187e..13958fb3f 100644 --- a/conference.js +++ b/conference.js @@ -9,7 +9,6 @@ import ConnectionQuality from './modules/connectionquality/connectionquality'; import CQEvents from './service/connectionquality/CQEvents'; import UIEvents from './service/UI/UIEvents'; -import DSEvents from './service/desktopsharing/DesktopSharingEventTypes'; const ConnectionEvents = JitsiMeetJS.events.connection; const ConnectionErrors = JitsiMeetJS.errors.connection; @@ -18,6 +17,7 @@ const ConferenceEvents = JitsiMeetJS.events.conference; const ConferenceErrors = JitsiMeetJS.errors.conference; const TrackEvents = JitsiMeetJS.events.track; +const TrackErrors = JitsiMeetJS.errors.track; let room, connection, localTracks, localAudio, localVideo, roomLocker; @@ -108,6 +108,41 @@ function muteLocalVideo (muted) { } } +/** + * Create local tracks of specified types. + * @param {string[]} devices required track types ('audio', 'video' etc.) + * @returns {Promise} + */ +function createLocalTracks (...devices) { + return JitsiMeetJS.createLocalTracks({ + // copy array to avoid mutations inside library + devices: devices.slice(0), + resolution: config.resolution, + // adds any ff fake device settings if any + firefox_fake_device: config.firefox_fake_device + }).catch(function (err) { + console.error('failed to create local tracks', ...devices, err); + return Promise.reject(err); + }); +} + +/** + * Create local screen sharing track. + * Shows UI notification if Firefox extension is required. + * @returns {Promise} + */ +function createDesktopTrack () { + return createLocalTracks('desktop').catch(function (err) { + if (err === TrackErrors.FIREFOX_EXTENSION_NEEDED) { + APP.UI.showExtensionRequiredDialog( + config.desktopSharingFirefoxExtensionURL + ); + } + + return Promise.reject(err); + }); +} + class ConferenceConnector { constructor(resolve, reject) { this._resolve = resolve; @@ -232,6 +267,8 @@ export default { isModerator: false, audioMuted: false, videoMuted: false, + isSharingScreen: false, + isDesktopSharingEnabled: false, /** * Open new connection and join to the conference. * @param {object} options @@ -244,10 +281,12 @@ export default { return JitsiMeetJS.init(config).then(() => { return Promise.all([ - this.createLocalTracks('audio', 'video').catch(()=>{ - return this.createLocalTracks('audio'); - }).catch( - () => {return [];}), + // try to retrieve audio and video + createLocalTracks('audio', 'video') + // if failed then try to retrieve only audio + .catch(() => createLocalTracks('audio')) + // if audio also failed then just return empty array + .catch(() => []), connect() ]); }).then(([tracks, con]) => { @@ -255,6 +294,8 @@ export default { localTracks = tracks; connection = con; this._createRoom(); + this.isDesktopSharingEnabled = + JitsiMeetJS.isDesktopSharingEnabled(); // XXX The API will take care of disconnecting from the XMPP server // (and, thus, leaving the room) on unload. return new Promise((resolve, reject) => { @@ -262,24 +303,6 @@ export default { }); }); }, - /** - * Create local tracks of specified types. - * If we cannot obtain required tracks it will return empty array. - * @param {string[]} devices required track types ('audio', 'video' etc.) - * @returns {Promise} - */ - createLocalTracks (...devices) { - return JitsiMeetJS.createLocalTracks({ - // copy array to avoid mutations inside library - devices: devices.slice(0), - resolution: config.resolution, - // adds any ff fake device settings if any - firefox_fake_device: config.firefox_fake_device - }).catch(function (err) { - console.error('failed to create local tracks', ...devices, err); - return Promise.reject(err); - }); - }, /** * Check if id is id of the local user. * @param {string} id id to check @@ -456,6 +479,79 @@ export default { } return options; }, + + videoSwitchInProgress: false, + toggleScreenSharing () { + if (this.videoSwitchInProgress) { + console.warn("Switch in progress."); + return; + } + if (!this.isDesktopSharingEnabled) { + console.warn("Cannot toggle screen sharing: not supported."); + return; + } + + this.videoSwitchInProgress = true; + + if (this.isSharingScreen) { + // stop sharing desktop and share video + createLocalTracks('video').then(function ([stream]) { + return room.addTrack(stream); + }).then((stream) => { + if (localVideo) { + localVideo.stop(); + } + localVideo = stream; + this.videoMuted = stream.isMuted(); + APP.UI.setVideoMuted(this.localId, this.videoMuted); + + APP.UI.addLocalStream(stream); + console.log('sharing local video'); + }).catch((err) => { + localVideo = null; + console.error('failed to share local video', err); + }).then(() => { + this.videoSwitchInProgress = false; + this.isSharingScreen = false; + APP.UI.updateDesktopSharingButtons(); + }); + } else { + // stop sharing video and share desktop + createDesktopTrack().then(([stream]) => { + stream.on( + TrackEvents.TRACK_STOPPED, + () => { + // if stream was stopped during screensharing session + // then we should switch to video + // otherwise we stopped it because we already switched + // to video, so nothing to do here + if (this.isSharingScreen) { + this.toggleScreenSharing(); + } + } + ); + return room.addTrack(stream); + }).then((stream) => { + if (localVideo) { + localVideo.stop(); + } + localVideo = stream; + + this.videoMuted = stream.isMuted(); + APP.UI.setVideoMuted(this.localId, this.videoMuted); + + APP.UI.addLocalStream(stream); + + this.videoSwitchInProgress = false; + this.isSharingScreen = true; + APP.UI.updateDesktopSharingButtons(); + console.log('sharing local desktop'); + }).catch((err) => { + this.videoSwitchInProgress = false; + console.error('failed to share local desktop', err); + }); + } + }, /** * Setup interaction between conference and UI. */ @@ -799,45 +895,8 @@ export default { room.pinParticipant(id); }); - APP.UI.addListener(UIEvents.TOGGLE_SCREENSHARING, () => { - APP.desktopsharing.toggleScreenSharing(); - }); - - APP.desktopsharing.addListener(DSEvents.SWITCHING_DONE, - (isSharingScreen) => { - APP.UI.updateDesktopSharingButtons(isSharingScreen); - }); - - APP.desktopsharing.addListener(DSEvents.FIREFOX_EXTENSION_NEEDED, - (url) => { - APP.UI.showExtensionRequiredDialog(url); - }); - - APP.desktopsharing.addListener(DSEvents.NEW_STREAM_CREATED, - (track, callback) => { - const localCallback = (newTrack) => { - if(!newTrack || !localVideo || !newTrack.isLocal() || - newTrack !== localVideo) - return; - if(localVideo.isMuted() && - localVideo.videoType !== track.videoType) { - localVideo.mute(); - } - callback(); - if(room) - room.off(ConferenceEvents.TRACK_ADDED, localCallback); - }; - if(room) { - room.on(ConferenceEvents.TRACK_ADDED, localCallback); - } - if(localVideo) - localVideo.stop(); - localVideo = track; - room.addTrack(track); - if(!room) - localCallback(); - APP.UI.addLocalStream(track); - } + APP.UI.addListener( + UIEvents.TOGGLE_SCREENSHARING, this.toggleScreenSharing.bind(this) ); } }; diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 653ee6564..5883a7473 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -782,10 +782,9 @@ UI.setAudioLevel = function (id, lvl) { /** * Update state of desktop sharing buttons. - * @param {boolean} isSharingScreen if user is currently sharing his screen */ -UI.updateDesktopSharingButtons = function (isSharingScreen) { - Toolbar.changeDesktopSharingButtonState(isSharingScreen); +UI.updateDesktopSharingButtons = function () { + Toolbar.updateDesktopSharingButtonState(); }; /** diff --git a/modules/UI/toolbars/Toolbar.js b/modules/UI/toolbars/Toolbar.js index 9993d7c03..1d471e8b6 100644 --- a/modules/UI/toolbars/Toolbar.js +++ b/modules/UI/toolbars/Toolbar.js @@ -131,7 +131,7 @@ const buttonHandlers = { emitter.emit(UIEvents.ETHERPAD_CLICKED); }, "toolbar_button_desktopsharing": function () { - if (APP.desktopsharing.isUsingScreenStream) { + if (APP.conference.isSharingScreen) { AnalyticsAdapter.sendEvent('toolbar.screen.disabled'); } else { AnalyticsAdapter.sendEvent('toolbar.screen.enabled'); @@ -371,13 +371,12 @@ const Toolbar = { }, /** - * Sets the state of the button. The button has blue glow if desktop + * Update the state of the button. The button has blue glow if desktop * streaming is active. - * @param active the state of the desktop streaming. */ - changeDesktopSharingButtonState (active) { + updateDesktopSharingButtonState () { let button = $("#toolbar_button_desktopsharing"); - if (active) { + if (APP.conference.isSharingScreen) { button.addClass("glow"); } else { button.removeClass("glow"); diff --git a/modules/UI/toolbars/ToolbarToggler.js b/modules/UI/toolbars/ToolbarToggler.js index 7d0df57b0..16c6bb94e 100644 --- a/modules/UI/toolbars/ToolbarToggler.js +++ b/modules/UI/toolbars/ToolbarToggler.js @@ -7,7 +7,7 @@ let toolbarTimeoutObject; let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT; function showDesktopSharingButton() { - if (APP.desktopsharing.isDesktopSharingEnabled() && + if (APP.conference.isDesktopSharingEnabled && UIUtil.isButtonEnabled('desktop')) { $('#toolbar_button_desktopsharing').css({display: "inline-block"}); } else { diff --git a/modules/desktopsharing/desktopsharing.js b/modules/desktopsharing/desktopsharing.js deleted file mode 100644 index 5209a817d..000000000 --- a/modules/desktopsharing/desktopsharing.js +++ /dev/null @@ -1,134 +0,0 @@ -/* global APP, JitsiMeetJS, config */ -var EventEmitter = require("events"); -import DSEvents from '../../service/desktopsharing/DesktopSharingEventTypes'; - -const TrackEvents = JitsiMeetJS.events.track; - -/** - * Indicates that desktop stream is currently in use (for toggle purpose). - * @type {boolean} - */ -var isUsingScreenStream = false; - -/** - * Indicates that switch stream operation is in progress and prevent from - * triggering new events. - * @type {boolean} - */ -var switchInProgress = false; - -/** - * true if desktop sharing is enabled and false otherwise. - */ -var isEnabled = false; - -var eventEmitter = new EventEmitter(); - -function streamSwitchDone() { - switchInProgress = false; - eventEmitter.emit(DSEvents.SWITCHING_DONE, isUsingScreenStream); -} - -function newStreamCreated(track) { - eventEmitter.emit(DSEvents.NEW_STREAM_CREATED, track, streamSwitchDone); -} - -function getVideoStreamFailed(error) { - console.error("Failed to obtain the stream to switch to", error); - switchInProgress = false; - isUsingScreenStream = false; - newStreamCreated(null); -} - -function getDesktopStreamFailed(error) { - console.error("Failed to obtain the stream to switch to", error); - switchInProgress = false; -} - -function onEndedHandler() { - if (!switchInProgress && isUsingScreenStream) { - APP.desktopsharing.toggleScreenSharing(); - } -} - -module.exports = { - isUsingScreenStream: function () { - return isUsingScreenStream; - }, - /** - * Initializes the desktop sharing module. - * @param {boolean} true if desktop sharing feature is available - * and enabled. - */ - init: function (enabled) { - isEnabled = enabled; - }, - /** - * @returns {boolean} true if desktop sharing feature is available - * and enabled. - */ - isDesktopSharingEnabled: function () { - return isEnabled; - }, - addListener: function (type, listener) { - eventEmitter.on(type, listener); - }, - - removeListener: function (type, listener) { - eventEmitter.removeListener(type, listener); - }, - - /* - * Toggles screen sharing. - */ - toggleScreenSharing: function () { - if (switchInProgress) { - console.warn("Switch in progress."); - return; - } else if (!this.isDesktopSharingEnabled()) { - console.warn("Cannot toggle screen sharing: not supported."); - return; - } - switchInProgress = true; - let type; - if (!isUsingScreenStream) { - // Switch to desktop stream - type = "desktop"; - } else { - type = "video"; - } - var fail = (error) => { - if (type === 'desktop') { - getDesktopStreamFailed(error); - } else { - getVideoStreamFailed(error); - } - }; - APP.conference.createLocalTracks(type).then((tracks) => { - // FIXME does it mean that 'not track.length' == GUM failed ? - // And will this ever happen if promise is supposed to fail in GUM - // failed case ? - if (!tracks.length) { - fail(); - return; - } - let stream = tracks[0]; - - // We now use screen stream - isUsingScreenStream = type === "desktop"; - if (isUsingScreenStream) { - stream.on(TrackEvents.TRACK_STOPPED, onEndedHandler); - } - newStreamCreated(stream); - }).catch((error) => { - if(error === JitsiMeetJS.errors.track.FIREFOX_EXTENSION_NEEDED) - { - eventEmitter.emit( - DSEvents.FIREFOX_EXTENSION_NEEDED, - config.desktopSharingFirefoxExtensionURL); - return; - } - fail(error); - }); - } -}; diff --git a/modules/keyboardshortcut/keyboardshortcut.js b/modules/keyboardshortcut/keyboardshortcut.js index 48c7905a1..c28892182 100644 --- a/modules/keyboardshortcut/keyboardshortcut.js +++ b/modules/keyboardshortcut/keyboardshortcut.js @@ -13,8 +13,8 @@ function initShortcutHandlers() { 68: { character: "D", id: "toggleDesktopSharingPopover", - function: function() { - APP.desktopsharing.toggleScreenSharing(); + function: function () { + APP.conference.toggleScreenSharing(); } }, 70: { diff --git a/service/desktopsharing/DesktopSharingEventTypes.js b/service/desktopsharing/DesktopSharingEventTypes.js deleted file mode 100644 index d41aba69f..000000000 --- a/service/desktopsharing/DesktopSharingEventTypes.js +++ /dev/null @@ -1,11 +0,0 @@ -export default { - SWITCHING_DONE: "ds.switching_done", - - NEW_STREAM_CREATED: "ds.new_stream_created", - - /** - * An event which indicates that the jidesha extension for Firefox is - * needed to proceed with screen sharing, and that it is not installed. - */ - FIREFOX_EXTENSION_NEEDED: "ds.firefox_extension_needed" -};