Skip to content

Commit

Permalink
feat(remotecontrol): announce remotecontrol support
Browse files Browse the repository at this point in the history
  • Loading branch information
hristoterezov committed Jan 23, 2017
1 parent 896650d commit 0f33e59
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 47 deletions.
6 changes: 3 additions & 3 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import conference from './conference';
import API from './modules/API/API';

import translation from "./modules/translation/translation";
// For remote control testing:
// import remoteControlController from "./modules/remotecontrol/Controller";
import remoteControl from "./modules/remotecontrol/remotecontrol";

const APP = {
// Used by do_external_connect.js if we receive the attach data after
Expand Down Expand Up @@ -61,7 +60,8 @@ const APP = {
*/
ConferenceUrl : null,
connection: null,
API
API,
remoteControl
};

// TODO The execution of the mobile app starts from react/index.native.js.
Expand Down
1 change: 1 addition & 0 deletions conference.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ export default {
}).then(([tracks, con]) => {
logger.log('initialized with %s local tracks', tracks.length);
APP.connection = connection = con;
APP.remoteControl.init();
this._bindConnectionFailedHandler(con);
this._createRoom(tracks);
this.isDesktopSharingEnabled =
Expand Down
45 changes: 31 additions & 14 deletions modules/API/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ function initCommands() {
APP.conference.toggleScreenSharing.bind(APP.conference),
"video-hangup": () => APP.conference.hangup(),
"email": APP.conference.changeLocalEmail,
"avatar-url": APP.conference.changeLocalAvatarUrl
"avatar-url": APP.conference.changeLocalAvatarUrl,
"remote-control-supported": isSupported =>
APP.remoteControl.onRemoteControlSupported(isSupported)
};
Object.keys(commands).forEach(function (key) {
postis.listen(key, args => commands[key](...args));
Expand Down Expand Up @@ -94,7 +96,13 @@ function triggerEvent (name, object) {
}
}

export default {
class API {
/**
* Constructs new instance
* @constructor
*/
constructor() { }

/**
* Initializes the APIConnector. Setups message event listeners that will
* receive information from external applications that embed Jitsi Meet.
Expand All @@ -108,6 +116,13 @@ export default {
return;

enabled = true;
}

/**
* initializes postis library.
* @private
*/
_initPostis() {
let postisOptions = {
window: target
};
Expand All @@ -116,15 +131,15 @@ export default {
= "jitsi_meet_external_api_" + jitsi_meet_external_api_id;
postis = postisInit(postisOptions);
initCommands();
},
}

/**
* Notify external application (if API is enabled) that message was sent.
* @param {string} body message body
*/
notifySendingChatMessage (body) {
triggerEvent("outgoing-message", {"message": body});
},
}

/**
* Notify external application (if API is enabled) that
Expand All @@ -143,7 +158,7 @@ export default {
"incoming-message",
{"from": id, "nick": nick, "message": body, "stamp": ts}
);
},
}

/**
* Notify external application (if API is enabled) that
Expand All @@ -152,7 +167,7 @@ export default {
*/
notifyUserJoined (id) {
triggerEvent("participant-joined", {id});
},
}

/**
* Notify external application (if API is enabled) that
Expand All @@ -161,7 +176,7 @@ export default {
*/
notifyUserLeft (id) {
triggerEvent("participant-left", {id});
},
}

/**
* Notify external application (if API is enabled) that
Expand All @@ -171,7 +186,7 @@ export default {
*/
notifyDisplayNameChanged (id, displayName) {
triggerEvent("display-name-change", {id, displayname: displayName});
},
}

/**
* Notify external application (if API is enabled) that
Expand All @@ -181,7 +196,7 @@ export default {
*/
notifyConferenceJoined (room) {
triggerEvent("video-conference-joined", {roomName: room});
},
}

/**
* Notify external application (if API is enabled) that
Expand All @@ -191,29 +206,31 @@ export default {
*/
notifyConferenceLeft (room) {
triggerEvent("video-conference-left", {roomName: room});
},
}

/**
* Notify external application (if API is enabled) that
* we are ready to be closed.
*/
notifyReadyToClose () {
triggerEvent("video-ready-to-close", {});
},
}

/**
* Sends remote control event.
* @param {object} event the event.
*/
sendRemoteControlEvent(event) {
sendMessage({method: "remote-control-event", params: event});
},
}

/**
* Removes the listeners.
*/
dispose: function () {
dispose () {
if(enabled)
postis.destroy();
}
};
}

export default new API();
50 changes: 33 additions & 17 deletions modules/remotecontrol/Controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* global $, APP */
import * as KeyCodes from "../keycode/keycode";
import {EVENT_TYPES, API_EVENT_TYPE}
from "../../service/remotecontrol/Constants";

/**
* Extract the keyboard key from the keyboard event.
Expand Down Expand Up @@ -42,41 +44,56 @@ function getModifiers(event) {
* It listens for mouse and keyboard events and sends them to the receiver
* party of the remote control session.
*/
class Controller {
export default class Controller {
/**
* Creates new instance.
*/
constructor() {}
constructor() {
this.enabled = false;
}

/**
* Enables / Disables the remote control
* @param {boolean} enabled the new state.
*/
enable(enabled) {
this.enabled = enabled;
}

/**
* Starts processing the mouse and keyboard events.
* @param {JQuery.selector} area the selector which will be used for
* attaching the listeners on.
*/
start(area) {
if(!this.enabled)
return;
this.area = area;
this.area.mousemove(event => {
const position = this.area.position();
this._sendEvent({
type: "mousemove",
this._sendRemoteControlEvent({
type: EVENT_TYPES.mousemove,
x: (event.pageX - position.left)/this.area.width(),
y: (event.pageY - position.top)/this.area.height()
});
});
this.area.mousedown(this._onMouseClickHandler.bind(this, "mousedown"));
this.area.mouseup(this._onMouseClickHandler.bind(this, "mouseup"));
this.area.mousedown(this._onMouseClickHandler.bind(this,
EVENT_TYPES.mousedown));
this.area.mouseup(this._onMouseClickHandler.bind(this,
EVENT_TYPES.mouseup));
this.area.dblclick(
this._onMouseClickHandler.bind(this, "mousedblclick"));
this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick));
this.area.contextmenu(() => false);
this.area[0].onmousewheel = event => {
this._sendEvent({
type: "mousescroll",
this._sendRemoteControlEvent({
type: EVENT_TYPES.mousescroll,
x: event.deltaX,
y: event.deltaY
});
};
$(window).keydown(this._onKeyPessHandler.bind(this, "keydown"));
$(window).keyup(this._onKeyPessHandler.bind(this, "keyup"));
$(window).keydown(this._onKeyPessHandler.bind(this,
EVENT_TYPES.keydown));
$(window).keyup(this._onKeyPessHandler.bind(this, EVENT_TYPES.keyup));
}

/**
Expand All @@ -99,7 +116,7 @@ class Controller {
* @param {Event} event the mouse event.
*/
_onMouseClickHandler(type, event) {
this._sendEvent({
this._sendRemoteControlEvent({
type: type,
button: event.which
});
Expand All @@ -111,7 +128,7 @@ class Controller {
* @param {Event} event the key event.
*/
_onKeyPessHandler(type, event) {
this._sendEvent({
this._sendRemoteControlEvent({
type: type,
key: getKey(event),
modifiers: getModifiers(event),
Expand All @@ -123,14 +140,13 @@ class Controller {
* @param {Object} event the remote control event.
*/
_sendRemoteControlEvent(event) {
if(!this.enabled)
return;
try{
APP.conference.sendEndpointMessage("",
{type: "remote-control-event", event});
{type: API_EVENT_TYPE, event});
} catch (e) {
// failed to send the event.
}
}
}


export default new Controller();
33 changes: 25 additions & 8 deletions modules/remotecontrol/Receiver.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* global APP, JitsiMeetJS */
import {DISCO_REMOTE_CONTROL_FEATURE, API_EVENT_TYPE}
from "../../service/remotecontrol/Constants";

const ConferenceEvents = JitsiMeetJS.events.conference;

/**
Expand All @@ -7,20 +10,36 @@ const ConferenceEvents = JitsiMeetJS.events.conference;
* API module. From there the events can be received from wrapper application
* and executed.
*/
class Receiver {
export default class Receiver {
/**
* Creates new instance.
* @constructor
*/
constructor() {}
constructor() {
this.enabled = false;
}

/**
* Enables / Disables the remote control
* @param {boolean} enabled the new state.
*/
enable(enabled) {
if(this.enabled !== enabled && enabled === true) {
this.enabled = enabled;
// Announce remote control support.
APP.connection.addFeature(DISCO_REMOTE_CONTROL_FEATURE, true);
}
}

/**
* Attaches listener for ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED events.
*/
start() {
APP.conference.addConferenceListener(
ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
this._onRemoteControlEvent);
if(this.enabled) {
APP.conference.addConferenceListener(
ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
this._onRemoteControlEvent);
}
}

/**
Expand All @@ -39,9 +58,7 @@ class Receiver {
* @param {Object} event the remote control event.
*/
_onRemoteControlEvent(participant, event) {
if(event.type === "remote-control-event")
if(event.type === API_EVENT_TYPE && this.enabled)
APP.API.sendRemoteControlEvent(event.event);
}
}

export default new Receiver();
51 changes: 51 additions & 0 deletions modules/remotecontrol/RemoteControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* global APP, config */
import Controller from "./Controller";
import Receiver from "./Receiver";

/**
* Implements the remote control functionality.
*/
class RemoteControl {
/**
* Constructs new instance. Creates controller and receiver properties.
* @constructor
*/
constructor() {
this.controller = new Controller();
this.receiver = new Receiver();
this.enabled = false;
this.initialized = false;
}

/**
* Initializes the remote control - checks if the remote control should be
* enabled or not, initializes the API module.
*/
init() {
if(config.disableRemoteControl || this.initialized) {
return;
}
this.initialized = true;
APP.API.init({
forceEnable: true,
});
this.controller.enable(true);
}

/**
* Handles API event for support for executing remote control events into
* the wrapper application.
* @param {boolean} isSupported true if the receiver side is supported by
* the wrapper application.
*/
onRemoteControlSupported(isSupported) {
if(isSupported && !config.disableRemoteControl) {
this.enabled = true;
if(this.initialized) {
this.receiver.enable(true);
}
}
}
}

export default new RemoteControl();
Loading

0 comments on commit 0f33e59

Please sign in to comment.