feat(remotecontrol): announce remotecontrol support
This commit is contained in:
parent
896650d005
commit
0f33e59e4d
6
app.js
6
app.js
|
@ -22,8 +22,7 @@ import conference from './conference';
|
||||||
import API from './modules/API/API';
|
import API from './modules/API/API';
|
||||||
|
|
||||||
import translation from "./modules/translation/translation";
|
import translation from "./modules/translation/translation";
|
||||||
// For remote control testing:
|
import remoteControl from "./modules/remotecontrol/remotecontrol";
|
||||||
// import remoteControlController from "./modules/remotecontrol/Controller";
|
|
||||||
|
|
||||||
const APP = {
|
const APP = {
|
||||||
// Used by do_external_connect.js if we receive the attach data after
|
// Used by do_external_connect.js if we receive the attach data after
|
||||||
|
@ -61,7 +60,8 @@ const APP = {
|
||||||
*/
|
*/
|
||||||
ConferenceUrl : null,
|
ConferenceUrl : null,
|
||||||
connection: null,
|
connection: null,
|
||||||
API
|
API,
|
||||||
|
remoteControl
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO The execution of the mobile app starts from react/index.native.js.
|
// TODO The execution of the mobile app starts from react/index.native.js.
|
||||||
|
|
|
@ -488,6 +488,7 @@ export default {
|
||||||
}).then(([tracks, con]) => {
|
}).then(([tracks, con]) => {
|
||||||
logger.log('initialized with %s local tracks', tracks.length);
|
logger.log('initialized with %s local tracks', tracks.length);
|
||||||
APP.connection = connection = con;
|
APP.connection = connection = con;
|
||||||
|
APP.remoteControl.init();
|
||||||
this._bindConnectionFailedHandler(con);
|
this._bindConnectionFailedHandler(con);
|
||||||
this._createRoom(tracks);
|
this._createRoom(tracks);
|
||||||
this.isDesktopSharingEnabled =
|
this.isDesktopSharingEnabled =
|
||||||
|
|
|
@ -55,7 +55,9 @@ function initCommands() {
|
||||||
APP.conference.toggleScreenSharing.bind(APP.conference),
|
APP.conference.toggleScreenSharing.bind(APP.conference),
|
||||||
"video-hangup": () => APP.conference.hangup(),
|
"video-hangup": () => APP.conference.hangup(),
|
||||||
"email": APP.conference.changeLocalEmail,
|
"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) {
|
Object.keys(commands).forEach(function (key) {
|
||||||
postis.listen(key, args => commands[key](...args));
|
postis.listen(key, args => commands[key](...args));
|
||||||
|
@ -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
|
* Initializes the APIConnector. Setups message event listeners that will
|
||||||
* receive information from external applications that embed Jitsi Meet.
|
* receive information from external applications that embed Jitsi Meet.
|
||||||
|
@ -108,6 +116,13 @@ export default {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
enabled = true;
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initializes postis library.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_initPostis() {
|
||||||
let postisOptions = {
|
let postisOptions = {
|
||||||
window: target
|
window: target
|
||||||
};
|
};
|
||||||
|
@ -116,7 +131,7 @@ export default {
|
||||||
= "jitsi_meet_external_api_" + jitsi_meet_external_api_id;
|
= "jitsi_meet_external_api_" + jitsi_meet_external_api_id;
|
||||||
postis = postisInit(postisOptions);
|
postis = postisInit(postisOptions);
|
||||||
initCommands();
|
initCommands();
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that message was sent.
|
* Notify external application (if API is enabled) that message was sent.
|
||||||
|
@ -124,7 +139,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifySendingChatMessage (body) {
|
notifySendingChatMessage (body) {
|
||||||
triggerEvent("outgoing-message", {"message": body});
|
triggerEvent("outgoing-message", {"message": body});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -143,7 +158,7 @@ export default {
|
||||||
"incoming-message",
|
"incoming-message",
|
||||||
{"from": id, "nick": nick, "message": body, "stamp": ts}
|
{"from": id, "nick": nick, "message": body, "stamp": ts}
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -152,7 +167,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifyUserJoined (id) {
|
notifyUserJoined (id) {
|
||||||
triggerEvent("participant-joined", {id});
|
triggerEvent("participant-joined", {id});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -161,7 +176,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifyUserLeft (id) {
|
notifyUserLeft (id) {
|
||||||
triggerEvent("participant-left", {id});
|
triggerEvent("participant-left", {id});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -171,7 +186,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifyDisplayNameChanged (id, displayName) {
|
notifyDisplayNameChanged (id, displayName) {
|
||||||
triggerEvent("display-name-change", {id, displayname: displayName});
|
triggerEvent("display-name-change", {id, displayname: displayName});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -181,7 +196,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifyConferenceJoined (room) {
|
notifyConferenceJoined (room) {
|
||||||
triggerEvent("video-conference-joined", {roomName: room});
|
triggerEvent("video-conference-joined", {roomName: room});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -191,7 +206,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifyConferenceLeft (room) {
|
notifyConferenceLeft (room) {
|
||||||
triggerEvent("video-conference-left", {roomName: room});
|
triggerEvent("video-conference-left", {roomName: room});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that
|
* Notify external application (if API is enabled) that
|
||||||
|
@ -199,7 +214,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
notifyReadyToClose () {
|
notifyReadyToClose () {
|
||||||
triggerEvent("video-ready-to-close", {});
|
triggerEvent("video-ready-to-close", {});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends remote control event.
|
* Sends remote control event.
|
||||||
|
@ -207,13 +222,15 @@ export default {
|
||||||
*/
|
*/
|
||||||
sendRemoteControlEvent(event) {
|
sendRemoteControlEvent(event) {
|
||||||
sendMessage({method: "remote-control-event", params: event});
|
sendMessage({method: "remote-control-event", params: event});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the listeners.
|
* Removes the listeners.
|
||||||
*/
|
*/
|
||||||
dispose: function () {
|
dispose () {
|
||||||
if(enabled)
|
if(enabled)
|
||||||
postis.destroy();
|
postis.destroy();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export default new API();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/* global $, APP */
|
/* global $, APP */
|
||||||
import * as KeyCodes from "../keycode/keycode";
|
import * as KeyCodes from "../keycode/keycode";
|
||||||
|
import {EVENT_TYPES, API_EVENT_TYPE}
|
||||||
|
from "../../service/remotecontrol/Constants";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the keyboard key from the keyboard event.
|
* Extract the keyboard key from the keyboard event.
|
||||||
|
@ -42,11 +44,21 @@ function getModifiers(event) {
|
||||||
* It listens for mouse and keyboard events and sends them to the receiver
|
* It listens for mouse and keyboard events and sends them to the receiver
|
||||||
* party of the remote control session.
|
* party of the remote control session.
|
||||||
*/
|
*/
|
||||||
class Controller {
|
export default class Controller {
|
||||||
/**
|
/**
|
||||||
* Creates new instance.
|
* 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.
|
* Starts processing the mouse and keyboard events.
|
||||||
|
@ -54,29 +66,34 @@ class Controller {
|
||||||
* attaching the listeners on.
|
* attaching the listeners on.
|
||||||
*/
|
*/
|
||||||
start(area) {
|
start(area) {
|
||||||
|
if(!this.enabled)
|
||||||
|
return;
|
||||||
this.area = area;
|
this.area = area;
|
||||||
this.area.mousemove(event => {
|
this.area.mousemove(event => {
|
||||||
const position = this.area.position();
|
const position = this.area.position();
|
||||||
this._sendEvent({
|
this._sendRemoteControlEvent({
|
||||||
type: "mousemove",
|
type: EVENT_TYPES.mousemove,
|
||||||
x: (event.pageX - position.left)/this.area.width(),
|
x: (event.pageX - position.left)/this.area.width(),
|
||||||
y: (event.pageY - position.top)/this.area.height()
|
y: (event.pageY - position.top)/this.area.height()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.area.mousedown(this._onMouseClickHandler.bind(this, "mousedown"));
|
this.area.mousedown(this._onMouseClickHandler.bind(this,
|
||||||
this.area.mouseup(this._onMouseClickHandler.bind(this, "mouseup"));
|
EVENT_TYPES.mousedown));
|
||||||
|
this.area.mouseup(this._onMouseClickHandler.bind(this,
|
||||||
|
EVENT_TYPES.mouseup));
|
||||||
this.area.dblclick(
|
this.area.dblclick(
|
||||||
this._onMouseClickHandler.bind(this, "mousedblclick"));
|
this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick));
|
||||||
this.area.contextmenu(() => false);
|
this.area.contextmenu(() => false);
|
||||||
this.area[0].onmousewheel = event => {
|
this.area[0].onmousewheel = event => {
|
||||||
this._sendEvent({
|
this._sendRemoteControlEvent({
|
||||||
type: "mousescroll",
|
type: EVENT_TYPES.mousescroll,
|
||||||
x: event.deltaX,
|
x: event.deltaX,
|
||||||
y: event.deltaY
|
y: event.deltaY
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
$(window).keydown(this._onKeyPessHandler.bind(this, "keydown"));
|
$(window).keydown(this._onKeyPessHandler.bind(this,
|
||||||
$(window).keyup(this._onKeyPessHandler.bind(this, "keyup"));
|
EVENT_TYPES.keydown));
|
||||||
|
$(window).keyup(this._onKeyPessHandler.bind(this, EVENT_TYPES.keyup));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,7 +116,7 @@ class Controller {
|
||||||
* @param {Event} event the mouse event.
|
* @param {Event} event the mouse event.
|
||||||
*/
|
*/
|
||||||
_onMouseClickHandler(type, event) {
|
_onMouseClickHandler(type, event) {
|
||||||
this._sendEvent({
|
this._sendRemoteControlEvent({
|
||||||
type: type,
|
type: type,
|
||||||
button: event.which
|
button: event.which
|
||||||
});
|
});
|
||||||
|
@ -111,7 +128,7 @@ class Controller {
|
||||||
* @param {Event} event the key event.
|
* @param {Event} event the key event.
|
||||||
*/
|
*/
|
||||||
_onKeyPessHandler(type, event) {
|
_onKeyPessHandler(type, event) {
|
||||||
this._sendEvent({
|
this._sendRemoteControlEvent({
|
||||||
type: type,
|
type: type,
|
||||||
key: getKey(event),
|
key: getKey(event),
|
||||||
modifiers: getModifiers(event),
|
modifiers: getModifiers(event),
|
||||||
|
@ -123,14 +140,13 @@ class Controller {
|
||||||
* @param {Object} event the remote control event.
|
* @param {Object} event the remote control event.
|
||||||
*/
|
*/
|
||||||
_sendRemoteControlEvent(event) {
|
_sendRemoteControlEvent(event) {
|
||||||
|
if(!this.enabled)
|
||||||
|
return;
|
||||||
try{
|
try{
|
||||||
APP.conference.sendEndpointMessage("",
|
APP.conference.sendEndpointMessage("",
|
||||||
{type: "remote-control-event", event});
|
{type: API_EVENT_TYPE, event});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// failed to send the event.
|
// failed to send the event.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default new Controller();
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
/* global APP, JitsiMeetJS */
|
/* global APP, JitsiMeetJS */
|
||||||
|
import {DISCO_REMOTE_CONTROL_FEATURE, API_EVENT_TYPE}
|
||||||
|
from "../../service/remotecontrol/Constants";
|
||||||
|
|
||||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,21 +10,37 @@ const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||||
* API module. From there the events can be received from wrapper application
|
* API module. From there the events can be received from wrapper application
|
||||||
* and executed.
|
* and executed.
|
||||||
*/
|
*/
|
||||||
class Receiver {
|
export default class Receiver {
|
||||||
/**
|
/**
|
||||||
* Creates new instance.
|
* Creates new instance.
|
||||||
* @constructor
|
* @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.
|
* Attaches listener for ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED events.
|
||||||
*/
|
*/
|
||||||
start() {
|
start() {
|
||||||
|
if(this.enabled) {
|
||||||
APP.conference.addConferenceListener(
|
APP.conference.addConferenceListener(
|
||||||
ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||||
this._onRemoteControlEvent);
|
this._onRemoteControlEvent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the listener for ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED
|
* Removes the listener for ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED
|
||||||
|
@ -39,9 +58,7 @@ class Receiver {
|
||||||
* @param {Object} event the remote control event.
|
* @param {Object} event the remote control event.
|
||||||
*/
|
*/
|
||||||
_onRemoteControlEvent(participant, event) {
|
_onRemoteControlEvent(participant, event) {
|
||||||
if(event.type === "remote-control-event")
|
if(event.type === API_EVENT_TYPE && this.enabled)
|
||||||
APP.API.sendRemoteControlEvent(event.event);
|
APP.API.sendRemoteControlEvent(event.event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Receiver();
|
|
||||||
|
|
|
@ -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();
|
|
@ -73,10 +73,6 @@ class TokenData{
|
||||||
|
|
||||||
this.jwt = jwt;
|
this.jwt = jwt;
|
||||||
|
|
||||||
//External API settings
|
|
||||||
this.externalAPISettings = {
|
|
||||||
forceEnable: true
|
|
||||||
};
|
|
||||||
this._decode();
|
this._decode();
|
||||||
// Use JWT param as token if there is not other token set and if the
|
// Use JWT param as token if there is not other token set and if the
|
||||||
// iss field is not anonymous. If you want to pass data with JWT token
|
// iss field is not anonymous. If you want to pass data with JWT token
|
||||||
|
|
|
@ -23,7 +23,7 @@ export function init() {
|
||||||
|
|
||||||
APP.keyboardshortcut = KeyboardShortcut;
|
APP.keyboardshortcut = KeyboardShortcut;
|
||||||
APP.tokenData = getTokenData();
|
APP.tokenData = getTokenData();
|
||||||
APP.API.init(APP.tokenData.externalAPISettings);
|
APP.API.init(APP.tokenData.jwt ? {forceEnable: true} : undefined);
|
||||||
|
|
||||||
APP.translation.init(settings.getLanguage());
|
APP.translation.init(settings.getLanguage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* The value for the "var" attribute of feature tag in disco-info packets.
|
||||||
|
*/
|
||||||
|
export const DISCO_REMOTE_CONTROL_FEATURE
|
||||||
|
= "http://jitsi.org/meet/remotecontrol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of remote-control-event events.
|
||||||
|
*/
|
||||||
|
export const EVENT_TYPES = {
|
||||||
|
mousemove: "mousemove",
|
||||||
|
mousedown: "mousedown",
|
||||||
|
mouseup: "mouseup",
|
||||||
|
mousedblclick: "mousedblclick",
|
||||||
|
mousescroll: "mousescroll",
|
||||||
|
keydown: "keydown",
|
||||||
|
keyup: "keyup"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of remote control events sent trough the API module.
|
||||||
|
*/
|
||||||
|
export const API_EVENT_TYPE = "remote-control-event";
|
Loading…
Reference in New Issue