Merge pull request #698 from jitsi/external_api
Changes the implementation of the iframe API to use postis
This commit is contained in:
commit
2e802c0f6d
|
@ -4,8 +4,6 @@ node_modules
|
||||||
*.iml
|
*.iml
|
||||||
.*.tmp
|
.*.tmp
|
||||||
deploy-local.sh
|
deploy-local.sh
|
||||||
libs/app.bundle.*
|
libs/
|
||||||
libs/lib-jitsi-meet*
|
|
||||||
libs/external_connect.js
|
|
||||||
all.css
|
all.css
|
||||||
.remote-sync.json
|
.remote-sync.json
|
||||||
|
|
13
Makefile
13
Makefile
|
@ -8,8 +8,9 @@ DEPLOY_DIR = libs
|
||||||
BROWSERIFY_FLAGS = -d
|
BROWSERIFY_FLAGS = -d
|
||||||
OUTPUT_DIR = .
|
OUTPUT_DIR = .
|
||||||
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
|
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
|
||||||
|
IFRAME_API_DIR = ./modules/API/external
|
||||||
|
|
||||||
all: update-deps compile uglify deploy clean
|
all: update-deps compile compile-iframe-api uglify uglify-iframe-api deploy clean
|
||||||
|
|
||||||
update-deps:
|
update-deps:
|
||||||
$(NPM) install
|
$(NPM) install
|
||||||
|
@ -17,8 +18,11 @@ update-deps:
|
||||||
compile:
|
compile:
|
||||||
$(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js
|
$(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js
|
||||||
|
|
||||||
|
compile-iframe-api:
|
||||||
|
$(BROWSERIFY) $(BROWSERIFY_FLAGS) -e $(IFRAME_API_DIR)/external_api.js -s JitsiMeetExternalAPI | $(EXORCIST) $(OUTPUT_DIR)/external_api.js.map > $(OUTPUT_DIR)/external_api.js
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OUTPUT_DIR)/app.bundle.*
|
rm -f $(OUTPUT_DIR)/app.bundle.* $(OUTPUT_DIR)/external_api.*
|
||||||
|
|
||||||
deploy: deploy-init deploy-appbundle deploy-lib-jitsi-meet deploy-css deploy-local
|
deploy: deploy-init deploy-appbundle deploy-lib-jitsi-meet deploy-css deploy-local
|
||||||
|
|
||||||
|
@ -28,6 +32,8 @@ deploy-init:
|
||||||
deploy-appbundle:
|
deploy-appbundle:
|
||||||
cp $(OUTPUT_DIR)/app.bundle.min.js $(OUTPUT_DIR)/app.bundle.min.map \
|
cp $(OUTPUT_DIR)/app.bundle.min.js $(OUTPUT_DIR)/app.bundle.min.map \
|
||||||
$(OUTPUT_DIR)/app.bundle.js $(OUTPUT_DIR)/app.bundle.js.map \
|
$(OUTPUT_DIR)/app.bundle.js $(OUTPUT_DIR)/app.bundle.js.map \
|
||||||
|
$(OUTPUT_DIR)/external_api.js.map $(OUTPUT_DIR)/external_api.js \
|
||||||
|
$(OUTPUT_DIR)/external_api.min.map $(OUTPUT_DIR)/external_api.min.js \
|
||||||
$(DEPLOY_DIR)
|
$(DEPLOY_DIR)
|
||||||
|
|
||||||
deploy-lib-jitsi-meet:
|
deploy-lib-jitsi-meet:
|
||||||
|
@ -46,6 +52,9 @@ deploy-local:
|
||||||
uglify:
|
uglify:
|
||||||
$(UGLIFYJS) -p relative $(OUTPUT_DIR)/app.bundle.js -o $(OUTPUT_DIR)/app.bundle.min.js --source-map $(OUTPUT_DIR)/app.bundle.min.map --in-source-map $(OUTPUT_DIR)/app.bundle.js.map
|
$(UGLIFYJS) -p relative $(OUTPUT_DIR)/app.bundle.js -o $(OUTPUT_DIR)/app.bundle.min.js --source-map $(OUTPUT_DIR)/app.bundle.min.map --in-source-map $(OUTPUT_DIR)/app.bundle.js.map
|
||||||
|
|
||||||
|
uglify-iframe-api:
|
||||||
|
$(UGLIFYJS) -p relative $(OUTPUT_DIR)/external_api.js -o $(OUTPUT_DIR)/external_api.min.js --source-map $(OUTPUT_DIR)/external_api.min.map --in-source-map $(OUTPUT_DIR)/external_api.js.map
|
||||||
|
|
||||||
|
|
||||||
source-package:
|
source-package:
|
||||||
mkdir -p source_package/jitsi-meet/css && \
|
mkdir -p source_package/jitsi-meet/css && \
|
||||||
|
|
5
app.js
5
app.js
|
@ -116,10 +116,7 @@ function init() {
|
||||||
APP.keyboardshortcut.init();
|
APP.keyboardshortcut.init();
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
APP.UI.hideRingOverLay();
|
APP.UI.hideRingOverLay();
|
||||||
APP.API.sendPostisMessage({
|
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||||
method: 'video-conference-left',
|
|
||||||
params: {roomName: APP.conference.roomName}
|
|
||||||
});
|
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,10 +155,7 @@ function maybeRedirectToWelcomePage() {
|
||||||
function disconnectAndShowFeedback(requestFeedback) {
|
function disconnectAndShowFeedback(requestFeedback) {
|
||||||
APP.UI.hideRingOverLay();
|
APP.UI.hideRingOverLay();
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
APP.API.sendPostisMessage({
|
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||||
method: 'video-conference-left',
|
|
||||||
params: {roomName: APP.conference.roomName}
|
|
||||||
});
|
|
||||||
if (requestFeedback) {
|
if (requestFeedback) {
|
||||||
return APP.UI.requestFeedback();
|
return APP.UI.requestFeedback();
|
||||||
} else {
|
} else {
|
||||||
|
@ -465,9 +462,6 @@ export default {
|
||||||
this._createRoom(tracks);
|
this._createRoom(tracks);
|
||||||
this.isDesktopSharingEnabled =
|
this.isDesktopSharingEnabled =
|
||||||
JitsiMeetJS.isDesktopSharingEnabled();
|
JitsiMeetJS.isDesktopSharingEnabled();
|
||||||
if(this.isDesktopSharingEnabled)
|
|
||||||
APP.API.addPostisMessageListener('toggle-share-screen',
|
|
||||||
() => this.toggleScreenSharing());
|
|
||||||
|
|
||||||
// if user didn't give access to mic or camera or doesn't have
|
// if user didn't give access to mic or camera or doesn't have
|
||||||
// them at all, we disable corresponding toolbar buttons
|
// them at all, we disable corresponding toolbar buttons
|
||||||
|
@ -908,10 +902,7 @@ export default {
|
||||||
// add local streams when joined to the conference
|
// add local streams when joined to the conference
|
||||||
room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
|
room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
|
||||||
APP.UI.mucJoined();
|
APP.UI.mucJoined();
|
||||||
APP.API.sendPostisMessage({
|
APP.API.notifyConferenceJoined(APP.conference.roomName);
|
||||||
method: 'video-conference-joined',
|
|
||||||
params: {roomName: APP.conference.roomName}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
room.on(
|
room.on(
|
||||||
|
|
37
doc/api.md
37
doc/api.md
|
@ -20,13 +20,13 @@ The next step for embedding Jitsi Meet is to create the Jitsi Meet API object
|
||||||
var height = 700;
|
var height = 700;
|
||||||
var api = new JitsiMeetExternalAPI(domain, room, width, height);
|
var api = new JitsiMeetExternalAPI(domain, room, width, height);
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
You can paste that lines in your html code where you want to be placed the Jitsi Meet conference
|
You can paste that lines in your html code where you want to be placed the Jitsi Meet conference
|
||||||
or you can specify the parent HTML element for the Jitsi Meet conference in the JitsiMeetExternalAPI
|
or you can specify the parent HTML element for the Jitsi Meet conference in the JitsiMeetExternalAPI
|
||||||
constructor.
|
constructor.
|
||||||
```javascript
|
```javascript
|
||||||
var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement);
|
var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement);
|
||||||
```
|
```
|
||||||
If you don't specify room the user will enter in new conference with random room name.
|
If you don't specify room the user will enter in new conference with random room name.
|
||||||
|
|
||||||
You can overwrite options set in config.js and interface_config.js. For example, to enable the film-strip-only interface mode and disable simulcast, you can use:
|
You can overwrite options set in config.js and interface_config.js. For example, to enable the film-strip-only interface mode and disable simulcast, you can use:
|
||||||
|
@ -34,24 +34,24 @@ You can overwrite options set in config.js and interface_config.js. For example,
|
||||||
var configOverwrite = {enableSimulcast: false};
|
var configOverwrite = {enableSimulcast: false};
|
||||||
var interfaceConfigOverwrite = {filmStripOnly: true};
|
var interfaceConfigOverwrite = {filmStripOnly: true};
|
||||||
var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement, true, configOverwrite, interfaceConfigOverwrite);
|
var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement, true, configOverwrite, interfaceConfigOverwrite);
|
||||||
```
|
```
|
||||||
|
|
||||||
Controlling embedded Jitsi Meet Conference
|
Controlling embedded Jitsi Meet Conference
|
||||||
=========
|
=========
|
||||||
|
|
||||||
You can control the embedded Jitsi Meet conference using the JitsiMeetExternalAPI object.
|
You can control the embedded Jitsi Meet conference using the JitsiMeetExternalAPI object.
|
||||||
|
|
||||||
You can send command to Jitsi Meet conference using ```executeCommand```.
|
You can send command to Jitsi Meet conference using ```executeCommand```.
|
||||||
```
|
```
|
||||||
api.executeCommand(command, arguments)
|
api.executeCommand(command, arguments)
|
||||||
```
|
```
|
||||||
The ```command``` parameter is String object with the name of the command.
|
The ```command``` parameter is String object with the name of the command.
|
||||||
The ```arguments``` parameter is array with the arguments required by the command.
|
The ```arguments``` parameter is array with the arguments required by the command.
|
||||||
If no arguments are required by the command this parameter can be omitted or you can pass empty array.
|
If no arguments are required by the command this parameter can be omitted or you can pass empty array.
|
||||||
Currently we support the following commands:
|
Currently we support the following commands:
|
||||||
|
|
||||||
|
|
||||||
* **displayName** - sets the display name of the local participant. This command requires one argument -
|
* **displayName** - sets the display name of the local participant. This command requires one argument -
|
||||||
the new display name to be set
|
the new display name to be set
|
||||||
```
|
```
|
||||||
api.executeCommand('displayName', ['New Nickname']);
|
api.executeCommand('displayName', ['New Nickname']);
|
||||||
|
@ -77,7 +77,12 @@ api.executeCommand('toggleChat', [])
|
||||||
api.executeCommand('toggleContactList', [])
|
api.executeCommand('toggleContactList', [])
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also execute multiple commands using the method ```executeCommands```.
|
* **toggleShareScreen** - starts / stops the screen sharing. No arguments are required.
|
||||||
|
```
|
||||||
|
api.executeCommand('toggleShareScreen', [])
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also execute multiple commands using the method ```executeCommands```.
|
||||||
```
|
```
|
||||||
api.executeCommands(commands)
|
api.executeCommands(commands)
|
||||||
```
|
```
|
||||||
|
@ -136,9 +141,23 @@ The listener will receive object with the following structure:
|
||||||
jid: jid //the jid of the participant
|
jid: jid //the jid of the participant
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
* **video-conference-joined** - event notifications fired when the local user has joined the video conference.
|
||||||
|
The listener will receive object with the following structure:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
roomName: room //the room name of the conference
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* **video-conference-left** - event notifications fired when the local user has left the video conference.
|
||||||
|
The listener will receive object with the following structure:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
roomName: room //the room name of the conference
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You can also add multiple event listeners by using ```addEventListeners```.
|
You can also add multiple event listeners by using ```addEventListeners```.
|
||||||
This method requires one argument of type Object. The object argument must
|
This method requires one argument of type Object. The object argument must
|
||||||
have keys with the names of the events and values the listeners of the events.
|
have keys with the names of the events and values the listeners of the events.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -173,4 +192,4 @@ You can remove the embedded Jitsi Meet Conference with the following code:
|
||||||
api.dispose()
|
api.dispose()
|
||||||
```
|
```
|
||||||
|
|
||||||
It is a good practice to remove the conference before the page is unloaded.
|
It is a good practice to remove the conference before the page is unloaded.
|
||||||
|
|
|
@ -33,6 +33,11 @@ server {
|
||||||
ssi on;
|
ssi on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Backward compatibility
|
||||||
|
location ~ /external_api.* {
|
||||||
|
root /usr/share/jitsi-meet/libs;
|
||||||
|
}
|
||||||
|
|
||||||
# BOSH
|
# BOSH
|
||||||
location /http-bind {
|
location /http-bind {
|
||||||
proxy_pass http://localhost:5280/http-bind;
|
proxy_pass http://localhost:5280/http-bind;
|
||||||
|
|
378
external_api.js
378
external_api.js
|
@ -1,378 +0,0 @@
|
||||||
/**
|
|
||||||
* Implements API class that embeds Jitsi Meet in external applications.
|
|
||||||
*/
|
|
||||||
var JitsiMeetExternalAPI = (function()
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The minimum width for the Jitsi Meet frame
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
var MIN_WIDTH = 790;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The minimum height for the Jitsi Meet frame
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
var MIN_HEIGHT = 300;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs new API instance. Creates iframe element that loads
|
|
||||||
* Jitsi Meet.
|
|
||||||
* @param domain the domain name of the server that hosts the conference
|
|
||||||
* @param room_name the name of the room to join
|
|
||||||
* @param width width of the iframe
|
|
||||||
* @param height height of the iframe
|
|
||||||
* @param parent_node the node that will contain the iframe
|
|
||||||
* @param filmStripOnly if the value is true only the small videos will be
|
|
||||||
* visible.
|
|
||||||
* @param noSsl if the value is true https won't be used
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode,
|
|
||||||
configOverwrite, interfaceConfigOverwrite, noSsl) {
|
|
||||||
if (!width || width < MIN_WIDTH)
|
|
||||||
width = MIN_WIDTH;
|
|
||||||
if (!height || height < MIN_HEIGHT)
|
|
||||||
height = MIN_HEIGHT;
|
|
||||||
|
|
||||||
this.parentNode = null;
|
|
||||||
if (parentNode) {
|
|
||||||
this.parentNode = parentNode;
|
|
||||||
} else {
|
|
||||||
var scriptTag = document.scripts[document.scripts.length - 1];
|
|
||||||
this.parentNode = scriptTag.parentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.iframeHolder =
|
|
||||||
this.parentNode.appendChild(document.createElement("div"));
|
|
||||||
this.iframeHolder.id = "jitsiConference" + JitsiMeetExternalAPI.id;
|
|
||||||
if(width)
|
|
||||||
this.iframeHolder.style.width = width + "px";
|
|
||||||
if(height)
|
|
||||||
this.iframeHolder.style.height = height + "px";
|
|
||||||
this.frameName = "jitsiConferenceFrame" + JitsiMeetExternalAPI.id;
|
|
||||||
this.url = (noSsl) ? "http" : "https" +"://" + domain + "/";
|
|
||||||
if(room_name)
|
|
||||||
this.url += room_name;
|
|
||||||
this.url += "#external=true";
|
|
||||||
|
|
||||||
var key;
|
|
||||||
if (configOverwrite) {
|
|
||||||
for (key in configOverwrite) {
|
|
||||||
if (!configOverwrite.hasOwnProperty(key) ||
|
|
||||||
typeof key !== 'string')
|
|
||||||
continue;
|
|
||||||
this.url += "&config." + key + "=" + configOverwrite[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interfaceConfigOverwrite) {
|
|
||||||
for (key in interfaceConfigOverwrite) {
|
|
||||||
if (!interfaceConfigOverwrite.hasOwnProperty(key) ||
|
|
||||||
typeof key !== 'string')
|
|
||||||
continue;
|
|
||||||
this.url += "&interfaceConfig." + key + "=" +
|
|
||||||
interfaceConfigOverwrite[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JitsiMeetExternalAPI.id++;
|
|
||||||
|
|
||||||
this.frame = document.createElement("iframe");
|
|
||||||
this.frame.src = this.url;
|
|
||||||
this.frame.name = this.frameName;
|
|
||||||
this.frame.id = this.frameName;
|
|
||||||
this.frame.width = "100%";
|
|
||||||
this.frame.height = "100%";
|
|
||||||
this.frame.setAttribute("allowFullScreen","true");
|
|
||||||
this.frame = this.iframeHolder.appendChild(this.frame);
|
|
||||||
|
|
||||||
|
|
||||||
this.frameLoaded = false;
|
|
||||||
this.initialCommands = [];
|
|
||||||
this.eventHandlers = {};
|
|
||||||
this.initListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Last id of api object
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.id = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the passed object to Jitsi Meet
|
|
||||||
* @param object the object to be sent
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.sendMessage = function(object) {
|
|
||||||
if (this.frameLoaded) {
|
|
||||||
this.frame.contentWindow.postMessage(
|
|
||||||
JSON.stringify(object), this.frame.src);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.initialCommands.push(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes command. The available commands are:
|
|
||||||
* displayName - sets the display name of the local participant to the value
|
|
||||||
* passed in the arguments array.
|
|
||||||
* toggleAudio - mutes / unmutes audio with no arguments
|
|
||||||
* toggleVideo - mutes / unmutes video with no arguments
|
|
||||||
* filmStrip - hides / shows the film strip with no arguments
|
|
||||||
* If the command doesn't require any arguments the parameter should be set
|
|
||||||
* to empty array or it may be omitted.
|
|
||||||
* @param name the name of the command
|
|
||||||
* @param arguments array of arguments
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.executeCommand = function(name,
|
|
||||||
argumentsList) {
|
|
||||||
var argumentsArray = argumentsList;
|
|
||||||
if (!argumentsArray)
|
|
||||||
argumentsArray = [];
|
|
||||||
var object = {type: "command", action: "execute"};
|
|
||||||
object[name] = argumentsArray;
|
|
||||||
this.sendMessage(object);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes commands. The available commands are:
|
|
||||||
* displayName - sets the display name of the local participant to the value
|
|
||||||
* passed in the arguments array.
|
|
||||||
* toggleAudio - mutes / unmutes audio with no arguments
|
|
||||||
* toggleVideo - mutes / unmutes video with no arguments
|
|
||||||
* filmStrip - hides / shows the film strip with no arguments
|
|
||||||
* @param object the object with commands to be executed. The keys of the
|
|
||||||
* object are the commands that will be executed and the values are the
|
|
||||||
* arguments for the command.
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.executeCommands = function (object) {
|
|
||||||
object.type = "command";
|
|
||||||
object.action = "execute";
|
|
||||||
this.sendMessage(object);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds event listeners to Meet Jitsi. The object key should be the name of
|
|
||||||
* the event and value - the listener.
|
|
||||||
* Currently we support the following
|
|
||||||
* events:
|
|
||||||
* incomingMessage - receives event notifications about incoming
|
|
||||||
* messages. The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* "from": from,//JID of the user that sent the message
|
|
||||||
* "nick": nick,//the nickname of the user that sent the message
|
|
||||||
* "message": txt//the text of the message
|
|
||||||
* }}
|
|
||||||
* outgoingMessage - receives event notifications about outgoing
|
|
||||||
* messages. The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* "message": txt//the text of the message
|
|
||||||
* }}
|
|
||||||
* displayNameChanged - receives event notifications about display name
|
|
||||||
* change. The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* jid: jid,//the JID of the participant that changed his display name
|
|
||||||
* displayname: displayName //the new display name
|
|
||||||
* }}
|
|
||||||
* participantJoined - receives event notifications about new participant.
|
|
||||||
* The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* jid: jid //the jid of the participant
|
|
||||||
* }}
|
|
||||||
* participantLeft - receives event notifications about the participant that
|
|
||||||
* left the room.
|
|
||||||
* The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* jid: jid //the jid of the participant
|
|
||||||
* }}
|
|
||||||
* @param object
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.addEventListeners
|
|
||||||
= function (object) {
|
|
||||||
|
|
||||||
var message = {type: "event", action: "add", events: []};
|
|
||||||
for(var i in object)
|
|
||||||
{
|
|
||||||
message.events.push(i);
|
|
||||||
this.eventHandlers[i] = object[i];
|
|
||||||
}
|
|
||||||
this.sendMessage(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds event listeners to Meet Jitsi. Currently we support the following
|
|
||||||
* events:
|
|
||||||
* incomingMessage - receives event notifications about incoming
|
|
||||||
* messages. The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* "from": from,//JID of the user that sent the message
|
|
||||||
* "nick": nick,//the nickname of the user that sent the message
|
|
||||||
* "message": txt//the text of the message
|
|
||||||
* }}
|
|
||||||
* outgoingMessage - receives event notifications about outgoing
|
|
||||||
* messages. The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* "message": txt//the text of the message
|
|
||||||
* }}
|
|
||||||
* displayNameChanged - receives event notifications about display name
|
|
||||||
* change. The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* jid: jid,//the JID of the participant that changed his display name
|
|
||||||
* displayname: displayName //the new display name
|
|
||||||
* }}
|
|
||||||
* participantJoined - receives event notifications about new participant.
|
|
||||||
* The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* jid: jid //the jid of the participant
|
|
||||||
* }}
|
|
||||||
* participantLeft - receives event notifications about participant the that
|
|
||||||
* left the room.
|
|
||||||
* The listener will receive object with the following structure:
|
|
||||||
* {{
|
|
||||||
* jid: jid //the jid of the participant
|
|
||||||
* }}
|
|
||||||
* @param event the name of the event
|
|
||||||
* @param listener the listener
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.addEventListener
|
|
||||||
= function (event, listener) {
|
|
||||||
|
|
||||||
var message = {type: "event", action: "add", events: [event]};
|
|
||||||
this.eventHandlers[event] = listener;
|
|
||||||
this.sendMessage(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes event listener.
|
|
||||||
* @param event the name of the event.
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.removeEventListener
|
|
||||||
= function (event) {
|
|
||||||
if(!this.eventHandlers[event])
|
|
||||||
{
|
|
||||||
console.error("The event " + event + " is not registered.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var message = {type: "event", action: "remove", events: [event]};
|
|
||||||
delete this.eventHandlers[event];
|
|
||||||
this.sendMessage(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes event listeners.
|
|
||||||
* @param events array with the names of the events.
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.removeEventListeners
|
|
||||||
= function (events) {
|
|
||||||
var eventsArray = [];
|
|
||||||
for(var i = 0; i < events.length; i++)
|
|
||||||
{
|
|
||||||
var event = events[i];
|
|
||||||
if(!this.eventHandlers[event])
|
|
||||||
{
|
|
||||||
console.error("The event " + event + " is not registered.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
delete this.eventHandlers[event];
|
|
||||||
eventsArray.push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(eventsArray.length > 0)
|
|
||||||
{
|
|
||||||
this.sendMessage(
|
|
||||||
{type: "event", action: "remove", events: eventsArray});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes message events sent from Jitsi Meet
|
|
||||||
* @param event the event
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.processMessage = function(event) {
|
|
||||||
var message;
|
|
||||||
try {
|
|
||||||
message = JSON.parse(event.data);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
if(!message.type) {
|
|
||||||
console.error("Message without type is received.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (message.type) {
|
|
||||||
case "system":
|
|
||||||
if(message.loaded) {
|
|
||||||
this.onFrameLoaded();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "event":
|
|
||||||
if(message.action != "result" ||
|
|
||||||
!message.event || !this.eventHandlers[message.event]) {
|
|
||||||
console.warn("The received event cannot be parsed.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.eventHandlers[message.event](message.result);
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
console.error("Unknown message type.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* That method is called when the Jitsi Meet is loaded. Executes saved
|
|
||||||
* commands that are send before the frame was loaded.
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.onFrameLoaded = function () {
|
|
||||||
this.frameLoaded = true;
|
|
||||||
for (var i = 0; i < this.initialCommands.length; i++) {
|
|
||||||
this.sendMessage(this.initialCommands[i]);
|
|
||||||
}
|
|
||||||
this.initialCommands = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setups the listener for message events from Jitsi Meet.
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.initListeners = function () {
|
|
||||||
var self = this;
|
|
||||||
this.eventListener = function (event) {
|
|
||||||
self.processMessage(event);
|
|
||||||
};
|
|
||||||
if (window.addEventListener) {
|
|
||||||
window.addEventListener('message',
|
|
||||||
this.eventListener, false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window.attachEvent('onmessage', this.eventListener);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the listeners and removes the Jitsi Meet frame.
|
|
||||||
*/
|
|
||||||
JitsiMeetExternalAPI.prototype.dispose = function () {
|
|
||||||
if (window.removeEventListener) {
|
|
||||||
window.removeEventListener('message',
|
|
||||||
this.eventListener, false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window.detachEvent('onmessage',
|
|
||||||
this.eventListener);
|
|
||||||
}
|
|
||||||
var frame = document.getElementById(this.frameName);
|
|
||||||
if(frame)
|
|
||||||
frame.src = 'about:blank';
|
|
||||||
var self = this;
|
|
||||||
window.setTimeout(function () {
|
|
||||||
self.iframeHolder.removeChild(self.frame);
|
|
||||||
self.iframeHolder.parentNode.removeChild(self.iframeHolder);
|
|
||||||
}, 10);
|
|
||||||
};
|
|
||||||
|
|
||||||
return JitsiMeetExternalAPI;
|
|
||||||
|
|
||||||
})();
|
|
|
@ -1,11 +1,11 @@
|
||||||
/* global APP */
|
/* global APP, getConfigParamsFromUrl */
|
||||||
/**
|
/**
|
||||||
* Implements API class that communicates with external api class
|
* Implements API class that communicates with external api class
|
||||||
* and provides interface to access Jitsi Meet features by external
|
* and provides interface to access Jitsi Meet features by external
|
||||||
* applications that embed Jitsi Meet
|
* applications that embed Jitsi Meet
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import postis from 'postis';
|
import postisInit from 'postis';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of the available commands.
|
* List of the available commands.
|
||||||
|
@ -20,36 +20,41 @@
|
||||||
*/
|
*/
|
||||||
let commands = {};
|
let commands = {};
|
||||||
|
|
||||||
|
let hashParams = getConfigParamsFromUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JitsiMeetExternalAPI id - unique for a webpage.
|
||||||
|
*/
|
||||||
|
let jitsi_meet_external_api_id = hashParams.jitsi_meet_external_api_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object that will execute sendMessage
|
* Object that will execute sendMessage
|
||||||
*/
|
*/
|
||||||
let target = window.opener ? window.opener : window.parent;
|
let target = window.opener ? window.opener : window.parent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of functions that are going to receive the objects passed to this
|
* Postis instance. Used to communicate with the external application.
|
||||||
* window
|
|
||||||
*/
|
*/
|
||||||
let messageListeners = [];
|
let postis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current status (enabled/disabled) of Postis.
|
* Current status (enabled/disabled) of API.
|
||||||
*/
|
*/
|
||||||
let enablePostis = false;
|
let enabled = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Current status (enabled/disabled) of Post Message API.
|
|
||||||
*/
|
|
||||||
let enablePostMessage = false;
|
|
||||||
|
|
||||||
function initCommands() {
|
function initCommands() {
|
||||||
commands = {
|
commands = {
|
||||||
displayName: APP.UI.inputDisplayNameHandler,
|
"display-name": APP.UI.inputDisplayNameHandler,
|
||||||
toggleAudio: APP.conference.toggleAudioMuted,
|
"toggle-audio": APP.conference.toggleAudioMuted,
|
||||||
toggleVideo: APP.conference.toggleVideoMuted,
|
"toggle-video": APP.conference.toggleVideoMuted,
|
||||||
toggleFilmStrip: APP.UI.toggleFilmStrip,
|
"toggle-film-strip": APP.UI.toggleFilmStrip,
|
||||||
toggleChat: APP.UI.toggleChat,
|
"toggle-chat": APP.UI.toggleChat,
|
||||||
toggleContactList: APP.UI.toggleContactList
|
"toggle-contact-list": APP.UI.toggleContactList,
|
||||||
|
"toggle-share-screen": APP.conference.toggleScreenSharing
|
||||||
};
|
};
|
||||||
|
Object.keys(commands).forEach(function (key) {
|
||||||
|
postis.listen(key, commands[key]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,95 +62,34 @@ function initCommands() {
|
||||||
* Maps the supported events and their status
|
* Maps the supported events and their status
|
||||||
* (true it the event is enabled and false if it is disabled)
|
* (true it the event is enabled and false if it is disabled)
|
||||||
* @type {{
|
* @type {{
|
||||||
* incomingMessage: boolean,
|
* incoming-message: boolean,
|
||||||
* outgoingMessage: boolean,
|
* outgoing-message: boolean,
|
||||||
* displayNameChange: boolean,
|
* display-name-change: boolean,
|
||||||
* participantJoined: boolean,
|
* participant-left: boolean,
|
||||||
* participantLeft: boolean
|
* participant-joined: boolean,
|
||||||
|
* video-conference-left: boolean,
|
||||||
|
* video-conference-joined: boolean
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
const events = {
|
const events = {
|
||||||
incomingMessage: false,
|
"incoming-message": false,
|
||||||
outgoingMessage:false,
|
"outgoing-message":false,
|
||||||
displayNameChange: false,
|
"display-name-change": false,
|
||||||
participantJoined: false,
|
"participant-joined": false,
|
||||||
participantLeft: false
|
"participant-left": false,
|
||||||
|
"video-conference-joined": false,
|
||||||
|
"video-conference-left": false
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes commands from external application.
|
|
||||||
* @param message the object with the command
|
|
||||||
*/
|
|
||||||
function processCommand(message) {
|
|
||||||
if (message.action != "execute") {
|
|
||||||
console.error("Unknown action of the message");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (var key in message) {
|
|
||||||
if(commands[key])
|
|
||||||
commands[key].apply(null, message[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes events objects from external applications
|
|
||||||
* @param event the event
|
|
||||||
*/
|
|
||||||
function processEvent(event) {
|
|
||||||
if (!event.action) {
|
|
||||||
console.error("Event with no action is received.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
switch(event.action) {
|
|
||||||
case "add":
|
|
||||||
for (; i < event.events.length; i++) {
|
|
||||||
events[event.events[i]] = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "remove":
|
|
||||||
for (; i < event.events.length; i++) {
|
|
||||||
events[event.events[i]] = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error("Unknown action for event.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes a message event from the external application
|
|
||||||
* @param event the message event
|
|
||||||
*/
|
|
||||||
function processMessage(event) {
|
|
||||||
var message;
|
|
||||||
try {
|
|
||||||
message = JSON.parse(event.data);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Cannot parse data", event.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message.type) {
|
|
||||||
case "command":
|
|
||||||
processCommand(message);
|
|
||||||
break;
|
|
||||||
case "event":
|
|
||||||
processEvent(message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.warn("Unknown message type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends message to the external application.
|
* Sends message to the external application.
|
||||||
* @param object {object} the object that will be sent as JSON string
|
* @param message {object}
|
||||||
|
* @param method {string}
|
||||||
|
* @param params {object} the object that will be sent as JSON string
|
||||||
*/
|
*/
|
||||||
function sendMessage(object) {
|
function sendMessage(message) {
|
||||||
if(enablePostMessage)
|
if(enabled)
|
||||||
target.postMessage(JSON.stringify(object), "*");
|
postis.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,8 +97,7 @@ function sendMessage(object) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function isEnabled () {
|
function isEnabled () {
|
||||||
let hash = location.hash;
|
return (typeof jitsi_meet_external_api_id === "number");
|
||||||
return !!(hash && hash.indexOf("external=true") > -1 && window.postMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,13 +116,25 @@ function isEventEnabled (name) {
|
||||||
* @param object data associated with the event
|
* @param object data associated with the event
|
||||||
*/
|
*/
|
||||||
function triggerEvent (name, object) {
|
function triggerEvent (name, object) {
|
||||||
if (isEventEnabled(name) && enablePostMessage) {
|
if(isEventEnabled(name))
|
||||||
sendMessage({
|
sendMessage({method: name, params: object});
|
||||||
type: "event",
|
}
|
||||||
action: "result",
|
|
||||||
event: name,
|
/**
|
||||||
result: object
|
* Handles system messages. (for example: enable/disable events)
|
||||||
});
|
* @param message {object} the message
|
||||||
|
*/
|
||||||
|
function onSystemMessage(message) {
|
||||||
|
switch (message.type) {
|
||||||
|
case "eventStatus":
|
||||||
|
if(!message.name || !message.value) {
|
||||||
|
console.warn("Unknown system message format", message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events[message.name] = message.value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn("Unknown system message type", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,33 +145,27 @@ export default {
|
||||||
* It also sends a message to the external application that APIConnector
|
* It also sends a message to the external application that APIConnector
|
||||||
* is initialized.
|
* is initialized.
|
||||||
* @param options {object}
|
* @param options {object}
|
||||||
* @param enablePostis {boolean} if true the postis npm
|
* @param forceEnable {boolean} if true the module will be enabled.
|
||||||
* package for comminication with the parent window will be enabled.
|
* @param enabledEvents {array} array of events that should be enabled.
|
||||||
* @param enablePostMessage {boolean} if true the postMessageAPI for
|
|
||||||
* comminication with the parent window will be enabled.
|
|
||||||
*/
|
*/
|
||||||
init: function (options = {}) {
|
init (options = {}) {
|
||||||
options.enablePostMessage = options.enablePostMessage || isEnabled();
|
if(!isEnabled() && !options.forceEnable)
|
||||||
if (!options.enablePostis &&
|
|
||||||
!options.enablePostMessage) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
enablePostis = options.enablePostis;
|
|
||||||
enablePostMessage = options.enablePostMessage;
|
|
||||||
|
|
||||||
if(enablePostMessage) {
|
enabled = true;
|
||||||
initCommands();
|
if(options.enabledEvents)
|
||||||
if (window.addEventListener) {
|
options.enabledEvents.forEach(function (eventName) {
|
||||||
window.addEventListener('message', processMessage, false);
|
events[eventName] = true;
|
||||||
} else {
|
});
|
||||||
window.attachEvent('onmessage', processMessage);
|
let postisOptions = {
|
||||||
}
|
window: target
|
||||||
sendMessage({type: "system", loaded: true});
|
};
|
||||||
}
|
if(typeof jitsi_meet_external_api_id === "number")
|
||||||
|
postisOptions.scope
|
||||||
if(enablePostis) {
|
= "jitsi_meet_external_api_" + jitsi_meet_external_api_id;
|
||||||
this.postis = postis({window: target});
|
postis = postisInit(postisOptions);
|
||||||
}
|
postis.listen("jitsiSystemMessage", onSystemMessage);
|
||||||
|
initCommands();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,28 +173,7 @@ export default {
|
||||||
* @param {string} body message body
|
* @param {string} body message body
|
||||||
*/
|
*/
|
||||||
notifySendingChatMessage (body) {
|
notifySendingChatMessage (body) {
|
||||||
triggerEvent("outgoingMessage", {"message": body});
|
triggerEvent("outgoing-message", {"message": body});
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends message to the external application.
|
|
||||||
* @param options {object}
|
|
||||||
* @param method {string}
|
|
||||||
* @param params {object} the object that will be sent as JSON string
|
|
||||||
*/
|
|
||||||
sendPostisMessage(options) {
|
|
||||||
if(enablePostis)
|
|
||||||
this.postis.send(options);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds listener for Postis messages.
|
|
||||||
* @param method {string} postis mehtod
|
|
||||||
* @param listener {function}
|
|
||||||
*/
|
|
||||||
addPostisMessageListener (method, listener) {
|
|
||||||
if(enablePostis)
|
|
||||||
this.postis.listen(method, listener);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -262,7 +190,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerEvent(
|
triggerEvent(
|
||||||
"incomingMessage",
|
"incoming-message",
|
||||||
{"from": id, "nick": nick, "message": body, "stamp": ts}
|
{"from": id, "nick": nick, "message": body, "stamp": ts}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -273,7 +201,7 @@ export default {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
*/
|
*/
|
||||||
notifyUserJoined (id) {
|
notifyUserJoined (id) {
|
||||||
triggerEvent("participantJoined", {id});
|
triggerEvent("participant-joined", {id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -282,7 +210,7 @@ export default {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
*/
|
*/
|
||||||
notifyUserLeft (id) {
|
notifyUserLeft (id) {
|
||||||
triggerEvent("participantLeft", {id});
|
triggerEvent("participant-left", {id});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,21 +220,34 @@ export default {
|
||||||
* @param {string} displayName user nickname
|
* @param {string} displayName user nickname
|
||||||
*/
|
*/
|
||||||
notifyDisplayNameChanged (id, displayName) {
|
notifyDisplayNameChanged (id, displayName) {
|
||||||
triggerEvent("displayNameChange", {id, displayname: displayName});
|
triggerEvent("display-name-change", {id, displayname: displayName});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify external application (if API is enabled) that
|
||||||
|
* user changed their nickname.
|
||||||
|
* @param {string} id user id
|
||||||
|
* @param {string} displayName user nickname
|
||||||
|
*/
|
||||||
|
notifyConferenceJoined (room) {
|
||||||
|
triggerEvent("video-conference-joined", {roomName: room});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify external application (if API is enabled) that
|
||||||
|
* user changed their nickname.
|
||||||
|
* @param {string} id user id
|
||||||
|
* @param {string} displayName user nickname
|
||||||
|
*/
|
||||||
|
notifyConferenceLeft (room) {
|
||||||
|
triggerEvent("video-conference-left", {roomName: room});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the listeners.
|
* Removes the listeners.
|
||||||
*/
|
*/
|
||||||
dispose: function () {
|
dispose: function () {
|
||||||
if (enablePostMessage) {
|
if(enabled)
|
||||||
if (window.removeEventListener) {
|
postis.destroy();
|
||||||
window.removeEventListener("message", processMessage, false);
|
|
||||||
} else {
|
|
||||||
window.detachEvent('onmessage', processMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(enablePostis)
|
|
||||||
this.postis.destroy();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,359 @@
|
||||||
|
/**
|
||||||
|
* Implements API class that embeds Jitsi Meet in external applications.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var postisInit = require("postis");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum width for the Jitsi Meet frame
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
var MIN_WIDTH = 790;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum height for the Jitsi Meet frame
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
var MIN_HEIGHT = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last id of api object
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
var id = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the names of the commands expected by the API with the name of the
|
||||||
|
* commands expected by jitsi-meet
|
||||||
|
*/
|
||||||
|
var commands = {
|
||||||
|
"displayName": "display-name",
|
||||||
|
"toggleAudio": "toggle-audio",
|
||||||
|
"toggleVideo": "toggle-video",
|
||||||
|
"toggleFilmStrip": "toggle-film-strip",
|
||||||
|
"toggleChat": "toggle-chat",
|
||||||
|
"toggleContactList": "toggle-contact-list",
|
||||||
|
"toggleShareScreen": "toggle-share-screen"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the names of the events expected by the API with the name of the
|
||||||
|
* events expected by jitsi-meet
|
||||||
|
*/
|
||||||
|
var events = {
|
||||||
|
"incomingMessage": "incoming-message",
|
||||||
|
"outgoingMessage": "outgoing-message",
|
||||||
|
"displayNameChange": "display-name-change",
|
||||||
|
"participantJoined": "participant-joined",
|
||||||
|
"participantLeft": "participant-left",
|
||||||
|
"videoConferenceJoined": "video-conference-joined",
|
||||||
|
"videoConferenceLeft": "video-conference-left"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the passed object to Jitsi Meet
|
||||||
|
* @param postis {Postis object} the postis instance that is going to be used
|
||||||
|
* to send the message
|
||||||
|
* @param object the object to be sent
|
||||||
|
* - method {sting}
|
||||||
|
* - params {object}
|
||||||
|
*/
|
||||||
|
function sendMessage(postis, object) {
|
||||||
|
postis.send(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends message for event enable/disable status change.
|
||||||
|
* @param postis {Postis object} the postis instance that is going to be used.
|
||||||
|
* @param event {string} the name of the event
|
||||||
|
* @param status {boolean} true - enabled; false - disabled;
|
||||||
|
*/
|
||||||
|
function changeEventStatus(postis, event, status) {
|
||||||
|
if(!(event in events)) {
|
||||||
|
console.error("Not supported event name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendMessage(postis, {
|
||||||
|
method: "jitsiSystemMessage",
|
||||||
|
params: {type: "eventStatus", name: events[event], value: status}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs new API instance. Creates iframe element that loads
|
||||||
|
* Jitsi Meet.
|
||||||
|
* @param domain the domain name of the server that hosts the conference
|
||||||
|
* @param room_name the name of the room to join
|
||||||
|
* @param width width of the iframe
|
||||||
|
* @param height height of the iframe
|
||||||
|
* @param parent_node the node that will contain the iframe
|
||||||
|
* @param filmStripOnly if the value is true only the small videos will be
|
||||||
|
* visible.
|
||||||
|
* @param noSsl if the value is true https won't be used
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode,
|
||||||
|
configOverwrite, interfaceConfigOverwrite, noSsl) {
|
||||||
|
if (!width || width < MIN_WIDTH)
|
||||||
|
width = MIN_WIDTH;
|
||||||
|
if (!height || height < MIN_HEIGHT)
|
||||||
|
height = MIN_HEIGHT;
|
||||||
|
|
||||||
|
this.parentNode = null;
|
||||||
|
if (parentNode) {
|
||||||
|
this.parentNode = parentNode;
|
||||||
|
} else {
|
||||||
|
var scriptTag = document.scripts[document.scripts.length - 1];
|
||||||
|
this.parentNode = scriptTag.parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.iframeHolder =
|
||||||
|
this.parentNode.appendChild(document.createElement("div"));
|
||||||
|
this.iframeHolder.id = "jitsiConference" + id;
|
||||||
|
if(width)
|
||||||
|
this.iframeHolder.style.width = width + "px";
|
||||||
|
if(height)
|
||||||
|
this.iframeHolder.style.height = height + "px";
|
||||||
|
this.frameName = "jitsiConferenceFrame" + id;
|
||||||
|
this.url = (noSsl) ? "http" : "https" +"://" + domain + "/";
|
||||||
|
if(room_name)
|
||||||
|
this.url += room_name;
|
||||||
|
this.url += "#jitsi_meet_external_api_id=" + id;
|
||||||
|
|
||||||
|
var key;
|
||||||
|
if (configOverwrite) {
|
||||||
|
for (key in configOverwrite) {
|
||||||
|
if (!configOverwrite.hasOwnProperty(key) ||
|
||||||
|
typeof key !== 'string')
|
||||||
|
continue;
|
||||||
|
this.url += "&config." + key + "=" + configOverwrite[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interfaceConfigOverwrite) {
|
||||||
|
for (key in interfaceConfigOverwrite) {
|
||||||
|
if (!interfaceConfigOverwrite.hasOwnProperty(key) ||
|
||||||
|
typeof key !== 'string')
|
||||||
|
continue;
|
||||||
|
this.url += "&interfaceConfig." + key + "=" +
|
||||||
|
interfaceConfigOverwrite[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.frame = document.createElement("iframe");
|
||||||
|
this.frame.src = this.url;
|
||||||
|
this.frame.name = this.frameName;
|
||||||
|
this.frame.id = this.frameName;
|
||||||
|
this.frame.width = "100%";
|
||||||
|
this.frame.height = "100%";
|
||||||
|
this.frame.setAttribute("allowFullScreen","true");
|
||||||
|
this.frame = this.iframeHolder.appendChild(this.frame);
|
||||||
|
this.postis = postisInit({
|
||||||
|
window: this.frame.contentWindow,
|
||||||
|
scope: "jitsi_meet_external_api_" + id
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventHandlers = {};
|
||||||
|
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes command. The available commands are:
|
||||||
|
* displayName - sets the display name of the local participant to the value
|
||||||
|
* passed in the arguments array.
|
||||||
|
* toggleAudio - mutes / unmutes audio with no arguments
|
||||||
|
* toggleVideo - mutes / unmutes video with no arguments
|
||||||
|
* filmStrip - hides / shows the film strip with no arguments
|
||||||
|
* If the command doesn't require any arguments the parameter should be set
|
||||||
|
* to empty array or it may be omitted.
|
||||||
|
* @param name the name of the command
|
||||||
|
* @param arguments array of arguments
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.executeCommand = function(name, argumentsList) {
|
||||||
|
if(!(name in commands)) {
|
||||||
|
console.error("Not supported command name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var argumentsArray = argumentsList;
|
||||||
|
if (!argumentsArray)
|
||||||
|
argumentsArray = [];
|
||||||
|
sendMessage(this.postis, {method: commands[name], params: argumentsArray});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes commands. The available commands are:
|
||||||
|
* displayName - sets the display name of the local participant to the value
|
||||||
|
* passed in the arguments array.
|
||||||
|
* toggleAudio - mutes / unmutes audio. no arguments
|
||||||
|
* toggleVideo - mutes / unmutes video. no arguments
|
||||||
|
* filmStrip - hides / shows the film strip. no arguments
|
||||||
|
* toggleChat - hides / shows chat. no arguments.
|
||||||
|
* toggleContactList - hides / shows contact list. no arguments.
|
||||||
|
* toggleShareScreen - starts / stops screen sharing. no arguments.
|
||||||
|
* @param object the object with commands to be executed. The keys of the
|
||||||
|
* object are the commands that will be executed and the values are the
|
||||||
|
* arguments for the command.
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.executeCommands = function(object) {
|
||||||
|
for(var key in object)
|
||||||
|
this.executeCommand(key, object[key]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event listeners to Meet Jitsi. The object key should be the name of
|
||||||
|
* the event and value - the listener.
|
||||||
|
* Currently we support the following
|
||||||
|
* events:
|
||||||
|
* incomingMessage - receives event notifications about incoming
|
||||||
|
* messages. The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* "from": from,//JID of the user that sent the message
|
||||||
|
* "nick": nick,//the nickname of the user that sent the message
|
||||||
|
* "message": txt//the text of the message
|
||||||
|
* }}
|
||||||
|
* outgoingMessage - receives event notifications about outgoing
|
||||||
|
* messages. The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* "message": txt//the text of the message
|
||||||
|
* }}
|
||||||
|
* displayNameChanged - receives event notifications about display name
|
||||||
|
* change. The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* jid: jid,//the JID of the participant that changed his display name
|
||||||
|
* displayname: displayName //the new display name
|
||||||
|
* }}
|
||||||
|
* participantJoined - receives event notifications about new participant.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* jid: jid //the jid of the participant
|
||||||
|
* }}
|
||||||
|
* participantLeft - receives event notifications about the participant that
|
||||||
|
* left the room.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* jid: jid //the jid of the participant
|
||||||
|
* }}
|
||||||
|
* video-conference-joined - receives event notifications about the local user
|
||||||
|
* has successfully joined the video conference.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* roomName: room //the room name of the conference
|
||||||
|
* }}
|
||||||
|
* video-conference-left - receives event notifications about the local user
|
||||||
|
* has left the video conference.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* roomName: room //the room name of the conference
|
||||||
|
* }}
|
||||||
|
* @param object
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.addEventListeners = function(object) {
|
||||||
|
for(var i in object)
|
||||||
|
this.addEventListener(i, object[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event listeners to Meet Jitsi. Currently we support the following
|
||||||
|
* events:
|
||||||
|
* incomingMessage - receives event notifications about incoming
|
||||||
|
* messages. The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* "from": from,//JID of the user that sent the message
|
||||||
|
* "nick": nick,//the nickname of the user that sent the message
|
||||||
|
* "message": txt//the text of the message
|
||||||
|
* }}
|
||||||
|
* outgoingMessage - receives event notifications about outgoing
|
||||||
|
* messages. The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* "message": txt//the text of the message
|
||||||
|
* }}
|
||||||
|
* displayNameChanged - receives event notifications about display name
|
||||||
|
* change. The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* jid: jid,//the JID of the participant that changed his display name
|
||||||
|
* displayname: displayName //the new display name
|
||||||
|
* }}
|
||||||
|
* participantJoined - receives event notifications about new participant.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* jid: jid //the jid of the participant
|
||||||
|
* }}
|
||||||
|
* participantLeft - receives event notifications about participant the that
|
||||||
|
* left the room.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* jid: jid //the jid of the participant
|
||||||
|
* }}
|
||||||
|
* video-conference-joined - receives event notifications fired when the local
|
||||||
|
* user has joined the video conference.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* roomName: room //the room name of the conference
|
||||||
|
* }}
|
||||||
|
* video-conference-left - receives event notifications fired when the local
|
||||||
|
* user has joined the video conference.
|
||||||
|
* The listener will receive object with the following structure:
|
||||||
|
* {{
|
||||||
|
* roomName: room //the room name of the conference
|
||||||
|
* }}
|
||||||
|
* @param event the name of the event
|
||||||
|
* @param listener the listener
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.addEventListener = function(event, listener) {
|
||||||
|
if(!(event in events)) {
|
||||||
|
console.error("Not supported event name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We cannot remove listeners from postis that's why we are handling the
|
||||||
|
// callback that way.
|
||||||
|
if(!(event in this.eventHandlers))
|
||||||
|
this.postis.listen(events[event], function(data) {
|
||||||
|
if((event in this.eventHandlers) &&
|
||||||
|
typeof this.eventHandlers[event] === "function")
|
||||||
|
this.eventHandlers[event].call(null, data);
|
||||||
|
}.bind(this));
|
||||||
|
this.eventHandlers[event] = listener;
|
||||||
|
changeEventStatus(this.postis, event, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes event listener.
|
||||||
|
* @param event the name of the event.
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.removeEventListener = function(event) {
|
||||||
|
if(!(event in this.eventHandlers))
|
||||||
|
{
|
||||||
|
console.error("The event " + event + " is not registered.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete this.eventHandlers[event];
|
||||||
|
changeEventStatus(this.postis, event, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes event listeners.
|
||||||
|
* @param events array with the names of the events.
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.removeEventListeners = function(events) {
|
||||||
|
var eventsArray = [];
|
||||||
|
for(var i = 0; i < events.length; i++)
|
||||||
|
this.removeEventListener(events[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the listeners and removes the Jitsi Meet frame.
|
||||||
|
*/
|
||||||
|
JitsiMeetExternalAPI.prototype.dispose = function() {
|
||||||
|
this.postis.dispose();
|
||||||
|
var frame = document.getElementById(this.frameName);
|
||||||
|
if(frame)
|
||||||
|
frame.src = 'about:blank';
|
||||||
|
var self = this;
|
||||||
|
window.setTimeout(function () {
|
||||||
|
self.iframeHolder.removeChild(self.frame);
|
||||||
|
self.iframeHolder.parentNode.removeChild(self.iframeHolder);
|
||||||
|
}, 10);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = JitsiMeetExternalAPI;
|
|
@ -72,7 +72,8 @@ class TokenData{
|
||||||
|
|
||||||
//External API settings
|
//External API settings
|
||||||
this.externalAPISettings = {
|
this.externalAPISettings = {
|
||||||
enablePostis: true
|
forceEnable: true,
|
||||||
|
enabledEvents: ["video-conference-joined", "video-conference-left"]
|
||||||
};
|
};
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue