diff --git a/conference.js b/conference.js index d3b6568b9..eac57d54a 100644 --- a/conference.js +++ b/conference.js @@ -2118,5 +2118,16 @@ export default { room.setDisplayName(formattedNickname); APP.UI.changeDisplayName(this.getMyUserId(), formattedNickname); } + }, + + /** + * Returns the desktop sharing source id or undefined if the desktop sharing + * is not active at the moment. + * + * @returns {string|undefined} - The source id. If the track is not desktop + * track or the source id is not available, undefined will be returned. + */ + getDesktopSharingSourceId() { + return localVideo.sourceId; } }; diff --git a/modules/remotecontrol/Controller.js b/modules/remotecontrol/Controller.js index f876cc591..c669fc652 100644 --- a/modules/remotecontrol/Controller.js +++ b/modules/remotecontrol/Controller.js @@ -4,9 +4,9 @@ import { getLogger } from 'jitsi-meet-logger'; import * as KeyCodes from '../keycode/keycode'; import { - EVENT_TYPES, + EVENTS, PERMISSIONS_ACTIONS, - REMOTE_CONTROL_EVENT_NAME + REMOTE_CONTROL_MESSAGE_NAME } from '../../service/remotecontrol/Constants'; import UIEvents from '../../service/UI/UIEvents'; @@ -145,8 +145,8 @@ export default class Controller extends RemoteControlParticipant { APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT, onUserLeft); this._requestedParticipant = userId; - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, + this.sendRemoteControlEndpointMessage(userId, { + type: EVENTS.permissions, action: PERMISSIONS_ACTIONS.request }, e => { clearRequest(); @@ -167,8 +167,8 @@ export default class Controller extends RemoteControlParticipant { const userId = participant.getId(); if (this._enabled - && event.name === REMOTE_CONTROL_EVENT_NAME - && event.type === EVENT_TYPES.permissions + && event.name === REMOTE_CONTROL_MESSAGE_NAME + && event.type === EVENTS.permissions && userId === this._requestedParticipant) { if (event.action !== PERMISSIONS_ACTIONS.grant) { this._area = undefined; @@ -201,13 +201,13 @@ export default class Controller extends RemoteControlParticipant { * event. * @param {Object} event - EndpointMessage event from the data channels. * @property {string} type - The function process only events with - * name REMOTE_CONTROL_EVENT_NAME. + * name REMOTE_CONTROL_MESSAGE_NAME. * @returns {void} */ _handleRemoteControlStoppedEvent(participant: Object, event: Object) { if (this._enabled - && event.name === REMOTE_CONTROL_EVENT_NAME - && event.type === EVENT_TYPES.stop + && event.name === REMOTE_CONTROL_MESSAGE_NAME + && event.type === EVENTS.stop && participant.getId() === this._controlledParticipant) { this._stop(); } @@ -251,8 +251,8 @@ export default class Controller extends RemoteControlParticipant { // $FlowDisableNextLine: we are sure that this._area is not null. const position = this._area.position(); - this.sendRemoteControlEvent(this._controlledParticipant, { - type: EVENT_TYPES.mousemove, + this.sendRemoteControlEndpointMessage(this._controlledParticipant, { + type: EVENTS.mousemove, // $FlowDisableNextLine: we are sure that this._area is not null x: (event.pageX - position.left) / this._area.width(), @@ -264,30 +264,30 @@ export default class Controller extends RemoteControlParticipant { // $FlowDisableNextLine: we are sure that this._area is not null. this._area.mousedown(this._onMouseClickHandler.bind(this, - EVENT_TYPES.mousedown)); + EVENTS.mousedown)); // $FlowDisableNextLine: we are sure that this._area is not null. this._area.mouseup(this._onMouseClickHandler.bind(this, - EVENT_TYPES.mouseup)); + EVENTS.mouseup)); // $FlowDisableNextLine: we are sure that this._area is not null. this._area.dblclick( - this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick)); + this._onMouseClickHandler.bind(this, EVENTS.mousedblclick)); // $FlowDisableNextLine: we are sure that this._area is not null. this._area.contextmenu(() => false); // $FlowDisableNextLine: we are sure that this._area is not null. this._area[0].onmousewheel = event => { - this.sendRemoteControlEvent(this._controlledParticipant, { - type: EVENT_TYPES.mousescroll, + this.sendRemoteControlEndpointMessage(this._controlledParticipant, { + type: EVENTS.mousescroll, x: event.deltaX, y: event.deltaY }); }; $(window).keydown(this._onKeyPessHandler.bind(this, - EVENT_TYPES.keydown)); - $(window).keyup(this._onKeyPessHandler.bind(this, EVENT_TYPES.keyup)); + EVENTS.keydown)); + $(window).keyup(this._onKeyPessHandler.bind(this, EVENTS.keyup)); } /** @@ -309,8 +309,8 @@ export default class Controller extends RemoteControlParticipant { this._stopListener); APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT, this._userLeftListener); - this._controlledParticipant = null; this.pause(); + this._controlledParticipant = null; this._area = undefined; APP.UI.messageHandler.openMessageDialog( 'dialog.remoteControlTitle', @@ -330,8 +330,8 @@ export default class Controller extends RemoteControlParticipant { if (!this._controlledParticipant) { return; } - this.sendRemoteControlEvent(this._controlledParticipant, { - type: EVENT_TYPES.stop + this.sendRemoteControlEndpointMessage(this._controlledParticipant, { + type: EVENTS.stop }); this._stop(); } @@ -383,7 +383,7 @@ export default class Controller extends RemoteControlParticipant { * @returns {void} */ _onMouseClickHandler(type: string, event: Object) { - this.sendRemoteControlEvent(this._controlledParticipant, { + this.sendRemoteControlEndpointMessage(this._controlledParticipant, { type, button: event.which }); @@ -416,7 +416,7 @@ export default class Controller extends RemoteControlParticipant { * @returns {void} */ _onKeyPessHandler(type: string, event: Object) { - this.sendRemoteControlEvent(this._controlledParticipant, { + this.sendRemoteControlEndpointMessage(this._controlledParticipant, { type, key: getKey(event), modifiers: getModifiers(event) diff --git a/modules/remotecontrol/Receiver.js b/modules/remotecontrol/Receiver.js index f84539f32..4b3c11607 100644 --- a/modules/remotecontrol/Receiver.js +++ b/modules/remotecontrol/Receiver.js @@ -8,9 +8,10 @@ import { } from '../../react/features/remote-control'; import { DISCO_REMOTE_CONTROL_FEATURE, - EVENT_TYPES, + EVENTS, PERMISSIONS_ACTIONS, - REMOTE_CONTROL_EVENT_NAME + REMOTE_CONTROL_MESSAGE_NAME, + REQUESTS } from '../../service/remotecontrol/Constants'; import { getJitsiMeetTransport } from '../transport'; @@ -51,14 +52,14 @@ export default class Receiver extends RemoteControlParticipant { super(); this._controller = null; this._remoteControlEventsListener - = this._onRemoteControlEvent.bind(this); + = this._onRemoteControlMessage.bind(this); this._userLeftListener = this._onUserLeft.bind(this); this._hangupListener = this._onHangup.bind(this); // We expect here that even if we receive the supported event earlier // it will be cached and we'll receive it. transport.on('event', event => { - if (event.name === REMOTE_CONTROL_EVENT_NAME) { + if (event.name === REMOTE_CONTROL_MESSAGE_NAME) { this._onRemoteControlAPIEvent(event); return true; @@ -120,12 +121,10 @@ export default class Receiver extends RemoteControlParticipant { this._controller = null; APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT, this._userLeftListener); - if (this.remoteControlExternalAuth) { - transport.sendEvent({ - name: REMOTE_CONTROL_EVENT_NAME, - type: EVENT_TYPES.stop - }); - } + transport.sendEvent({ + name: REMOTE_CONTROL_MESSAGE_NAME, + type: EVENTS.stop + }); if (!dontShowDialog) { APP.UI.messageHandler.openMessageDialog( 'dialog.remoteControlTitle', @@ -143,89 +142,46 @@ export default class Receiver extends RemoteControlParticipant { if (!this._controller) { return; } - this.sendRemoteControlEvent(this._controller, { - type: EVENT_TYPES.stop + this.sendRemoteControlEndpointMessage(this._controller, { + type: EVENTS.stop }); this._stop(); } /** - * Listens for data channel EndpointMessage events. Handles only events of - * type remote control. Sends "remote-control-event" events to the API - * module. + * Listens for data channel EndpointMessage. Handles only remote control + * messages. Sends the remote control messages to the external app that + * will execute them. * * @param {JitsiParticipant} participant - The controller participant. - * @param {Object} event - EndpointMessage event from the data channels. - * @param {string} event.name - The function process only events with - * name REMOTE_CONTROL_EVENT_NAME. + * @param {Object} message - EndpointMessage from the data channels. + * @param {string} message.name - The function processes only messages with + * name REMOTE_CONTROL_MESSAGE_NAME. * @returns {void} */ - _onRemoteControlEvent(participant: Object, event: Object) { - if (event.name !== REMOTE_CONTROL_EVENT_NAME) { + _onRemoteControlMessage(participant: Object, message: Object) { + if (message.name !== REMOTE_CONTROL_MESSAGE_NAME) { return; } - const remoteControlEvent = Object.assign({}, event); - if (this._enabled) { if (this._controller === null - && event.type === EVENT_TYPES.permissions - && event.action === PERMISSIONS_ACTIONS.request) { + && message.type === EVENTS.permissions + && message.action === PERMISSIONS_ACTIONS.request) { const userId = participant.getId(); - if (!config.remoteControlExternalAuth) { - APP.store.dispatch( - openRemoteControlAuthorizationDialog(userId)); - - return; + APP.store.dispatch( + openRemoteControlAuthorizationDialog(userId)); + } else if (this._controller === participant.getId()) { + if (message.type === EVENTS.stop) { + this._stop(); + } else { // forward the message + transport.sendEvent(message); } - - // FIXME: Maybe use transport.sendRequest in this case??? - remoteControlEvent.userId = userId; - remoteControlEvent.userJID = participant.getJid(); - remoteControlEvent.displayName = participant.getDisplayName() - || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME; - remoteControlEvent.screenSharing - = APP.conference.isSharingScreen; - } else if (this._controller !== participant.getId()) { - return; - } else if (event.type === EVENT_TYPES.stop) { - this._stop(); - - return; - } - transport.sendEvent(remoteControlEvent); + } // else ignore } else { - logger.log('Remote control event is ignored because remote ' - + 'control is disabled', event); - } - } - - /** - * Handles remote control permission events. - * - * @param {string} userId - The user id of the participant related to the - * event. - * @param {PERMISSIONS_ACTIONS} action - The action related to the event. - * @returns {void} - */ - _onRemoteControlPermissionsEvent(userId: string, action: string) { - switch (action) { - case PERMISSIONS_ACTIONS.grant: - this.grant(userId); - break; - case PERMISSIONS_ACTIONS.deny: - this.deny(userId); - break; - case PERMISSIONS_ACTIONS.error: - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, - action - }); - break; - default: - - // Unknown action. Ignore. + logger.log('Remote control message is ignored because remote ' + + 'control is disabled', message); } } @@ -237,8 +193,8 @@ export default class Receiver extends RemoteControlParticipant { * @returns {void} */ deny(userId: string) { - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, + this.sendRemoteControlEndpointMessage(userId, { + type: EVENTS.permissions, action: PERMISSIONS_ACTIONS.deny }); } @@ -255,50 +211,63 @@ export default class Receiver extends RemoteControlParticipant { this._userLeftListener); this._controller = userId; logger.log(`Remote control permissions granted to: ${userId}`); + + let promise; + if (APP.conference.isSharingScreen) { - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, - action: PERMISSIONS_ACTIONS.grant - }); + promise = this._sendStartRequest(); } else { - APP.conference.toggleScreenSharing() - .then(() => { - if (APP.conference.isSharingScreen) { - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, - action: PERMISSIONS_ACTIONS.grant - }); - } else { - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, - action: PERMISSIONS_ACTIONS.error - }); - } - }) - .catch(() => { - this.sendRemoteControlEvent(userId, { - type: EVENT_TYPES.permissions, - action: PERMISSIONS_ACTIONS.error - }); - }); + promise = APP.conference.toggleScreenSharing() + .then(() => this._sendStartRequest()); } + + promise + .then(() => + this.sendRemoteControlEndpointMessage(userId, { + type: EVENTS.permissions, + action: PERMISSIONS_ACTIONS.grant + }) + ) + .catch(() => { + this.sendRemoteControlEndpointMessage(userId, { + type: EVENTS.permissions, + action: PERMISSIONS_ACTIONS.error + }); + + // FIXME: show err msg + this._stop(); + }); + } + + /** + * Sends remote control start request. + * + * @returns {Promise} + */ + _sendStartRequest() { + return transport.sendRequest({ + name: REMOTE_CONTROL_MESSAGE_NAME, + type: REQUESTS.start, + sourceId: APP.conference.getDesktopSharingSourceId() + }); } /** * Handles remote control events from the external app. Currently only - * events with type = EVENT_TYPES.supported or EVENT_TYPES.permissions. + * events with type EVENTS.supported and EVENTS.stop are + * supported. * * @param {RemoteControlEvent} event - The remote control event. * @returns {void} */ _onRemoteControlAPIEvent(event: Object) { switch (event.type) { - case EVENT_TYPES.permissions: - this._onRemoteControlPermissionsEvent(event.userId, event.action); - break; - case EVENT_TYPES.supported: + case EVENTS.supported: this._onRemoteControlSupported(); break; + case EVENTS.stop: + this.stop(); + break; } } diff --git a/modules/remotecontrol/RemoteControlParticipant.js b/modules/remotecontrol/RemoteControlParticipant.js index 7d609c8cc..d85c36080 100644 --- a/modules/remotecontrol/RemoteControlParticipant.js +++ b/modules/remotecontrol/RemoteControlParticipant.js @@ -3,7 +3,7 @@ import { getLogger } from 'jitsi-meet-logger'; import { - REMOTE_CONTROL_EVENT_NAME + REMOTE_CONTROL_MESSAGE_NAME } from '../../service/remotecontrol/Constants'; const logger = getLogger(__filename); @@ -34,14 +34,14 @@ export default class RemoteControlParticipant { } /** - * Sends remote control event to other participant trough data channel. + * Sends remote control message to other participant trough data channel. * * @param {string} to - The participant who will receive the event. * @param {RemoteControlEvent} event - The remote control event. * @param {Function} onDataChannelFail - Handler for data channel failure. * @returns {void} */ - sendRemoteControlEvent( + sendRemoteControlEndpointMessage( to: ?string, event: Object, onDataChannelFail: ?Function) { @@ -55,7 +55,7 @@ export default class RemoteControlParticipant { } try { APP.conference.sendEndpointMessage(to, { - name: REMOTE_CONTROL_EVENT_NAME, + name: REMOTE_CONTROL_MESSAGE_NAME, ...event }); } catch (e) { diff --git a/service/remotecontrol/Constants.js b/service/remotecontrol/Constants.js index e295614c6..d80be7f6a 100644 --- a/service/remotecontrol/Constants.js +++ b/service/remotecontrol/Constants.js @@ -5,11 +5,11 @@ export const DISCO_REMOTE_CONTROL_FEATURE = "http://jitsi.org/meet/remotecontrol"; /** - * Types of remote-control-event events. + * Types of remote-control events. * @readonly * @enum {string} */ -export const EVENT_TYPES = { +export const EVENTS = { mousemove: "mousemove", mousedown: "mousedown", mouseup: "mouseup", @@ -18,10 +18,20 @@ export const EVENT_TYPES = { keydown: "keydown", keyup: "keyup", permissions: "permissions", + start: "start", stop: "stop", supported: "supported" }; +/** + * Types of remote-control requests. + * @readonly + * @enum {string} + */ +export const REQUESTS = { + start: "start" +}; + /** * Actions for the remote control permission events. * @readonly @@ -35,20 +45,20 @@ export const PERMISSIONS_ACTIONS = { }; /** - * The type of remote control events sent trough the API module. + * The type of remote control messages. */ -export const REMOTE_CONTROL_EVENT_NAME = "remote-control-event"; +export const REMOTE_CONTROL_MESSAGE_NAME = "remote-control"; /** * The remote control event. * @typedef {object} RemoteControlEvent - * @property {EVENT_TYPES} type - the type of the event - * @property {int} x - avaibale for type === mousemove only. The new x + * @property {EVENTS | REQUESTS} type - the type of the message + * @property {number} x - avaibale for type === mousemove only. The new x * coordinate of the mouse - * @property {int} y - For mousemove type - the new y + * @property {number} y - For mousemove type - the new y * coordinate of the mouse and for mousescroll - represents the vertical * scrolling diff value - * @property {int} button - 1(left), 2(middle) or 3 (right). Supported by + * @property {number} button - 1(left), 2(middle) or 3 (right). Supported by * mousedown, mouseup and mousedblclick types. * @property {KEYS} key - Represents the key related to the event. Supported by * keydown and keyup types.