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 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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -108,6 +116,13 @@ export default {
|
|||
return;
|
||||
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* initializes postis library.
|
||||
* @private
|
||||
*/
|
||||
_initPostis() {
|
||||
let postisOptions = {
|
||||
window: target
|
||||
};
|
||||
|
@ -116,7 +131,7 @@ 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.
|
||||
|
@ -124,7 +139,7 @@ export default {
|
|||
*/
|
||||
notifySendingChatMessage (body) {
|
||||
triggerEvent("outgoing-message", {"message": body});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -143,7 +158,7 @@ export default {
|
|||
"incoming-message",
|
||||
{"from": id, "nick": nick, "message": body, "stamp": ts}
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -152,7 +167,7 @@ export default {
|
|||
*/
|
||||
notifyUserJoined (id) {
|
||||
triggerEvent("participant-joined", {id});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -161,7 +176,7 @@ export default {
|
|||
*/
|
||||
notifyUserLeft (id) {
|
||||
triggerEvent("participant-left", {id});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -171,7 +186,7 @@ export default {
|
|||
*/
|
||||
notifyDisplayNameChanged (id, displayName) {
|
||||
triggerEvent("display-name-change", {id, displayname: displayName});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -181,7 +196,7 @@ export default {
|
|||
*/
|
||||
notifyConferenceJoined (room) {
|
||||
triggerEvent("video-conference-joined", {roomName: room});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -191,7 +206,7 @@ export default {
|
|||
*/
|
||||
notifyConferenceLeft (room) {
|
||||
triggerEvent("video-conference-left", {roomName: room});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
|
@ -199,7 +214,7 @@ export default {
|
|||
*/
|
||||
notifyReadyToClose () {
|
||||
triggerEvent("video-ready-to-close", {});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends remote control event.
|
||||
|
@ -207,13 +222,15 @@ export default {
|
|||
*/
|
||||
sendRemoteControlEvent(event) {
|
||||
sendMessage({method: "remote-control-event", params: event});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listeners.
|
||||
*/
|
||||
dispose: function () {
|
||||
dispose () {
|
||||
if(enabled)
|
||||
postis.destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new API();
|
||||
|
|
|
@ -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.
|
||||
|
@ -42,11 +44,21 @@ 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.
|
||||
|
@ -54,29 +66,34 @@ class Controller {
|
|||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +116,7 @@ class Controller {
|
|||
* @param {Event} event the mouse event.
|
||||
*/
|
||||
_onMouseClickHandler(type, event) {
|
||||
this._sendEvent({
|
||||
this._sendRemoteControlEvent({
|
||||
type: type,
|
||||
button: event.which
|
||||
});
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* global APP, JitsiMeetJS */
|
||||
import {DISCO_REMOTE_CONTROL_FEATURE, API_EVENT_TYPE}
|
||||
from "../../service/remotecontrol/Constants";
|
||||
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
//External API settings
|
||||
this.externalAPISettings = {
|
||||
forceEnable: true
|
||||
};
|
||||
this._decode();
|
||||
// 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
|
||||
|
|
|
@ -23,7 +23,7 @@ export function init() {
|
|||
|
||||
APP.keyboardshortcut = KeyboardShortcut;
|
||||
APP.tokenData = getTokenData();
|
||||
APP.API.init(APP.tokenData.externalAPISettings);
|
||||
APP.API.init(APP.tokenData.jwt ? {forceEnable: true} : undefined);
|
||||
|
||||
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