From 1a9a8a2098c49cc8db4cf8bbe53ff423098fecb6 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 7 Jul 2017 17:45:24 -0500 Subject: [PATCH 1/3] feat(SS): pass the source type to lib-jitsi-meet. --- conference.js | 12 +++++++ .../components/DesktopPicker.js | 35 +++++++++++++------ .../components/DesktopPickerPane.js | 3 +- .../components/DesktopSourcePreview.js | 15 ++++++-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/conference.js b/conference.js index eac57d54a..a2c08d21e 100644 --- a/conference.js +++ b/conference.js @@ -2129,5 +2129,17 @@ export default { */ getDesktopSharingSourceId() { return localVideo.sourceId; + }, + + /** + * Returns the desktop sharing source type or undefined if the desktop + * sharing is not active at the moment. + * + * @returns {'screen'|'window'|undefined} - The source type. If the track is + * not desktop track or the source type is not available, undefined will be + * returned. + */ + getDesktopSharingSourceType() { + return localVideo.sourceType; } }; diff --git a/react/features/desktop-picker/components/DesktopPicker.js b/react/features/desktop-picker/components/DesktopPicker.js index f734e4e6c..318d6a5c6 100644 --- a/react/features/desktop-picker/components/DesktopPicker.js +++ b/react/features/desktop-picker/components/DesktopPicker.js @@ -85,7 +85,7 @@ class DesktopPicker extends Component { super(props); this.state = { - selectedSourceId: '' + selectedSource: {} }; this._poller = null; @@ -116,10 +116,13 @@ class DesktopPicker extends Component { * @returns {void} */ componentWillReceiveProps(nextProps) { - if (!this.state.selectedSourceId + if (!this.state.selectedSource.id && nextProps.sources.screen.length) { this.setState({ - selectedSourceId: nextProps.sources.screen[0].id + selectedSource: { + id: nextProps.sources.screen[0].id, + type: 'screen' + } }); } } @@ -155,14 +158,16 @@ class DesktopPicker extends Component { /** * Dispatches an action to hide the DesktopPicker and invokes the passed in - * callback with a selectedSourceId, if any. + * callback with a selectedSource, if any. * * @param {string} id - The id of the DesktopCapturerSource to pass into the * onSourceChoose callback. + * @param {string} type - The type of the DesktopCapturerSource to pass into + * the onSourceChoose callback. * @returns {void} */ - _onCloseModal(id = '') { - this.props.onSourceChoose(id); + _onCloseModal(id, type) { + this.props.onSourceChoose(id, type); this.props.dispatch(hideDialog()); } @@ -170,10 +175,16 @@ class DesktopPicker extends Component { * Sets the currently selected DesktopCapturerSource. * * @param {string} id - The id of DesktopCapturerSource. + * @param {string} type - The type of DesktopCapturerSource. * @returns {void} */ - _onPreviewClick(id) { - this.setState({ selectedSourceId: id }); + _onPreviewClick(id, type) { + this.setState({ + selectedSource: { + id, + type + } + }); } /** @@ -183,7 +194,9 @@ class DesktopPicker extends Component { * @returns {void} */ _onSubmit() { - this._onCloseModal(this.state.selectedSourceId); + const { id, type } = this.state.selectedSource; + + this._onCloseModal(id, type); } /** @@ -193,7 +206,7 @@ class DesktopPicker extends Component { * @returns {ReactElement} */ _renderTabs() { - const { selectedSourceId } = this.state; + const { selectedSource } = this.state; const { sources, t } = this.props; const tabs = TABS_TO_POPULATE.map(({ defaultSelected, label, type }) => { @@ -202,7 +215,7 @@ class DesktopPicker extends Component { key = { type } onClick = { this._onPreviewClick } onDoubleClick = { this._onCloseModal } - selectedSourceId = { selectedSourceId } + selectedSourceId = { selectedSource.id } sources = { sources[type] || [] } type = { type } />, defaultSelected, diff --git a/react/features/desktop-picker/components/DesktopPickerPane.js b/react/features/desktop-picker/components/DesktopPickerPane.js index e4d1d1d9e..2112f0a13 100644 --- a/react/features/desktop-picker/components/DesktopPickerPane.js +++ b/react/features/desktop-picker/components/DesktopPickerPane.js @@ -66,7 +66,8 @@ class DesktopPickerPane extends Component { onClick = { onClick } onDoubleClick = { onDoubleClick } selected = { source.id === selectedSourceId } - source = { source } />); + source = { source } + type = { type } />); return (
diff --git a/react/features/desktop-picker/components/DesktopSourcePreview.js b/react/features/desktop-picker/components/DesktopSourcePreview.js index 76394f1a7..4b9a86706 100644 --- a/react/features/desktop-picker/components/DesktopSourcePreview.js +++ b/react/features/desktop-picker/components/DesktopSourcePreview.js @@ -34,7 +34,12 @@ class DesktopSourcePreview extends Component { /** * The DesktopCapturerSource to display. */ - source: React.PropTypes.object + source: React.PropTypes.object, + + /** + * The source type of the DesktopCapturerSources to display. + */ + type: React.PropTypes.string }; /** @@ -83,7 +88,9 @@ class DesktopSourcePreview extends Component { * @returns {void} */ _onClick() { - this.props.onClick(this.props.source.id); + const { source, type } = this.props; + + this.props.onClick(source.id, type); } /** @@ -92,7 +99,9 @@ class DesktopSourcePreview extends Component { * @returns {void} */ _onDoubleClick() { - this.props.onDoubleClick(this.props.source.id); + const { source, type } = this.props; + + this.props.onDoubleClick(source.id, type); } } From dc8198100b1cc9779ee230efee0389733313f975 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Sun, 9 Jul 2017 16:34:08 -0500 Subject: [PATCH 2/3] feat(remotecontrol): Make sure the receiver is always sharing entire screen --- conference.js | 13 +++- lang/main.json | 1 + modules/remotecontrol/Receiver.js | 21 ++++-- react/features/desktop-picker/actions.js | 4 +- .../components/DesktopPicker.js | 75 +++++++++++++------ .../RemoteControlAuthorizationDialog.js | 3 +- 6 files changed, 84 insertions(+), 33 deletions(-) diff --git a/conference.js b/conference.js index a2c08d21e..e23ed7a5c 100644 --- a/conference.js +++ b/conference.js @@ -87,8 +87,8 @@ import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/VideoContainer"; * lib-jitsi-meet to detect and invoke */ window.JitsiMeetScreenObtainer = { - openDesktopPicker(onSourceChoose) { - APP.store.dispatch(showDesktopPicker(onSourceChoose)); + openDesktopPicker(options, onSourceChoose) { + APP.store.dispatch(showDesktopPicker(options, onSourceChoose)); } }; @@ -341,6 +341,7 @@ function createLocalTracks(options, checkForPermissionPrompt) { .createLocalTracks({ // copy array to avoid mutations inside library devices: options.devices.slice(0), + desktopSharingSources: options.desktopSharingSources, resolution: config.resolution, cameraDeviceId: typeof options.cameraDeviceId === 'undefined' || options.cameraDeviceId === null @@ -1108,9 +1109,14 @@ export default { /** * Toggles between screensharing and camera video. * @param {boolean} [shareScreen] + * @param {Object} [options] - Screen sharing options that will be passed to + * createLocalTracks. + * @param {Array} [options.desktopSharingSources] - Array with the + * sources that have to be displayed in the desktop picker window ('screen', + * 'window', etc.). * @return {Promise.} */ - toggleScreenSharing(shareScreen = !this.isSharingScreen) { + toggleScreenSharing(shareScreen = !this.isSharingScreen, options = {}) { if (this.videoSwitchInProgress) { return Promise.reject('Switch in progress.'); } @@ -1130,6 +1136,7 @@ export default { if (shareScreen) { return createLocalTracks({ + desktopSharingSources: options.desktopSharingSources, devices: ['desktop'], desktopSharingExtensionExternalInstallation: { interval: 500, diff --git a/lang/main.json b/lang/main.json index aefe8a567..c78c11795 100644 --- a/lang/main.json +++ b/lang/main.json @@ -340,6 +340,7 @@ "remoteControlDeniedMessage": "__user__ rejected your remote control request!", "remoteControlAllowedMessage": "__user__ accepted your remote control request!", "remoteControlErrorMessage": "An error occurred while trying to request remote control permissions from __user__!", + "startRemoteControlErrorMessage": "An error occurred while trying to start the remote control session!", "remoteControlStopMessage": "The remote control session ended!", "close": "Close", "shareYourScreen": "Share your screen", diff --git a/modules/remotecontrol/Receiver.js b/modules/remotecontrol/Receiver.js index 4b3c11607..2e225eece 100644 --- a/modules/remotecontrol/Receiver.js +++ b/modules/remotecontrol/Receiver.js @@ -214,10 +214,15 @@ export default class Receiver extends RemoteControlParticipant { let promise; - if (APP.conference.isSharingScreen) { + if (APP.conference.isSharingScreen + && APP.conference.getDesktopSharingSourceType() === 'screen') { promise = this._sendStartRequest(); } else { - promise = APP.conference.toggleScreenSharing() + promise = APP.conference.toggleScreenSharing( + true, + { + desktopSharingSources: [ 'screen' ] + }) .then(() => this._sendStartRequest()); } @@ -228,14 +233,20 @@ export default class Receiver extends RemoteControlParticipant { action: PERMISSIONS_ACTIONS.grant }) ) - .catch(() => { + .catch(error => { + logger.error(error); + this.sendRemoteControlEndpointMessage(userId, { type: EVENTS.permissions, action: PERMISSIONS_ACTIONS.error }); - // FIXME: show err msg - this._stop(); + APP.UI.messageHandler.openMessageDialog( + 'dialog.remoteControlTitle', + 'dialog.startRemoteControlErrorMessage' + ); + + this._stop(true); }); } diff --git a/react/features/desktop-picker/actions.js b/react/features/desktop-picker/actions.js index 43d157d06..c8bed9774 100644 --- a/react/features/desktop-picker/actions.js +++ b/react/features/desktop-picker/actions.js @@ -62,12 +62,14 @@ export function resetDesktopSources() { /** * Signals to open a dialog with the DesktopPicker component. * + * @param {Object} options - Desktop sharing settings. * @param {Function} onSourceChoose - The callback to invoke when * a DesktopCapturerSource has been chosen. * @returns {Object} */ -export function showDesktopPicker(onSourceChoose) { +export function showDesktopPicker(options, onSourceChoose) { return openDialog(DesktopPicker, { + options, onSourceChoose }); } diff --git a/react/features/desktop-picker/components/DesktopPicker.js b/react/features/desktop-picker/components/DesktopPicker.js index 318d6a5c6..9b1a241a5 100644 --- a/react/features/desktop-picker/components/DesktopPicker.js +++ b/react/features/desktop-picker/components/DesktopPicker.js @@ -1,5 +1,3 @@ -/* global config */ - import Tabs from '@atlaskit/tabs'; import React, { Component } from 'react'; import { connect } from 'react-redux'; @@ -33,12 +31,7 @@ const TAB_CONFIGURATIONS = [ type: 'window' } ]; -const CONFIGURED_TYPES = config.desktopSharingChromeSources || []; const VALID_TYPES = TAB_CONFIGURATIONS.map(c => c.type); -const TABS_TO_POPULATE - = TAB_CONFIGURATIONS.filter( - c => CONFIGURED_TYPES.includes(c.type) && VALID_TYPES.includes(c.type)); -const TYPES_TO_FETCH = TABS_TO_POPULATE.map(c => c.type); /** * React component for DesktopPicker. @@ -63,6 +56,11 @@ class DesktopPicker extends Component { */ onSourceChoose: React.PropTypes.func, + /** + * An object with options related to desktop sharing. + */ + options: React.PropTypes.object, + /** * An object with arrays of DesktopCapturerSources. The key should be * the source type. @@ -85,7 +83,9 @@ class DesktopPicker extends Component { super(props); this.state = { - selectedSource: {} + selectedSource: {}, + tabsToPopulate: [], + typesToFetch: [] }; this._poller = null; @@ -102,6 +102,10 @@ class DesktopPicker extends Component { * @inheritdoc */ componentWillMount() { + const options = this.props.options || {}; + + this._onSourceTypesConfigChanged( + options.desktopSharingSources); this._updateSources(); this._startPolling(); } @@ -125,6 +129,11 @@ class DesktopPicker extends Component { } }); } + + const options = this.props.options || {}; + + this._onSourceTypesConfigChanged( + options.desktopSharingSources); } /** @@ -166,7 +175,7 @@ class DesktopPicker extends Component { * the onSourceChoose callback. * @returns {void} */ - _onCloseModal(id, type) { + _onCloseModal(id = '', type) { this.props.onSourceChoose(id, type); this.props.dispatch(hideDialog()); } @@ -209,19 +218,20 @@ class DesktopPicker extends Component { const { selectedSource } = this.state; const { sources, t } = this.props; const tabs - = TABS_TO_POPULATE.map(({ defaultSelected, label, type }) => { - return { - content: , - defaultSelected, - label: t(label) - }; - }); + = this.state.tabsToPopulate.map( + ({ defaultSelected, label, type }) => { + return { + content: , + defaultSelected, + label: t(label) + }; + }); return ; } @@ -248,6 +258,25 @@ class DesktopPicker extends Component { this._poller = null; } + /** + * Handles changing of allowed desktop sharing source types. + * + * @param {Array} desktopSharingSourceTypes - The types that will be + * fetched and displayed. + * @returns {void} + */ + _onSourceTypesConfigChanged(desktopSharingSourceTypes = []) { + const tabsToPopulate = TAB_CONFIGURATIONS.filter( + c => desktopSharingSourceTypes.includes(c.type) + && VALID_TYPES.includes(c.type) + ); + + this.setState({ + tabsToPopulate, + typesToFetch: tabsToPopulate.map(c => c.type) + }); + } + /** * Dispatches an action to get currently available DesktopCapturerSources. * @@ -256,7 +285,7 @@ class DesktopPicker extends Component { */ _updateSources() { this.props.dispatch(obtainDesktopSources( - TYPES_TO_FETCH, + this.state.typesToFetch, { THUMBNAIL_SIZE } diff --git a/react/features/remote-control/components/RemoteControlAuthorizationDialog.js b/react/features/remote-control/components/RemoteControlAuthorizationDialog.js index 796f7390c..a38d024a2 100644 --- a/react/features/remote-control/components/RemoteControlAuthorizationDialog.js +++ b/react/features/remote-control/components/RemoteControlAuthorizationDialog.js @@ -94,7 +94,8 @@ class RemoteControlAuthorizationDialog extends Component { _getAdditionalMessage() { // FIXME: Once we have this information in redux we should // start getting it from there. - if (APP.conference.isSharingScreen) { + if (APP.conference.isSharingScreen + && APP.conference.getDesktopSharingSourceType() === 'screen') { return null; } From 1498245b9e0b5e9dccc3ab8a7fae9a18ec11548f Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Sun, 9 Jul 2017 22:42:35 -0500 Subject: [PATCH 3/3] fix(remotecontrol): Show error on cancel of desktop picker --- conference.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/conference.js b/conference.js index e23ed7a5c..102b604ad 100644 --- a/conference.js +++ b/conference.js @@ -1183,24 +1183,25 @@ export default { JitsiMeetJS.analytics.sendEvent( 'conference.sharingDesktop.start'); logger.log('sharing local desktop'); - }).catch((err) => { + }).catch(err => { // close external installation dialog to show the error. if(externalInstallation) $.prompt.close(); this.videoSwitchInProgress = false; - this.toggleScreenSharing(false); if (err.name === TrackErrors.CHROME_EXTENSION_USER_CANCELED) { - return; + return Promise.reject(err); } + this.toggleScreenSharing(false); + logger.error('failed to share local desktop', err); if (err.name === TrackErrors.FIREFOX_EXTENSION_NEEDED) { APP.UI.showExtensionRequiredDialog( config.desktopSharingFirefoxExtensionURL ); - return; + return Promise.reject(err); } // Handling: