@ -1,40 +1,23 @@
const logger = require ( "jitsi-meet-logger" ) . getLogger ( _ _filename ) ;
import postisInit from "postis" ;
import EventEmitter from "events" ;
import EventEmitter from 'events' ;
import postisInit from 'postis' ;
/ * *
* The minimum width for the Jitsi Meet frame
* @ type { number }
* /
const MIN _WIDTH = 790 ;
/ * *
* The minimum height for the Jitsi Meet frame
* @ type { number }
* /
const MIN _HEIGHT = 300 ;
/ * *
* Last id of api object
* @ type { number }
* /
let id = 0 ;
const logger = require ( 'jitsi-meet-logger' ) . getLogger ( _ _filename ) ;
/ * *
* Maps the names of the commands expected by the API with the name of the
* commands expected by jitsi - meet
* /
const 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" ,
"hangup" : "video-hangup" ,
"email" : "email" ,
"avatarUrl" : "avatar-url"
avatarUrl : 'avatar-url' ,
displayName : 'display-name' ,
email : 'email' ,
hangup : 'video-hangup' ,
toggleAudio : 'toggle-audio' ,
toggleChat : 'toggle-chat' ,
toggleContactList : 'toggle-contact-list' ,
toggleFilmStrip : 'toggle-film-strip' ,
toggleShareScreen : 'toggle-share-screen' ,
toggleVideo : 'toggle-video'
} ;
/ * *
@ -42,35 +25,42 @@ const commands = {
* events expected by jitsi - meet
* /
const 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" ,
"readyToClose" : "video-ready-to-close"
displayNameChange : 'display-name-change' ,
incomingMessage : 'incoming-message' ,
outgoingMessage : 'outgoing-message' ,
participantJoined : 'participant-joined' ,
participantLeft : 'participant-left' ,
readyToClose : 'video-ready-to-close' ,
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 }
* Last id of api object
* @ type { number }
* /
function sendMessage ( postis , object ) {
postis . send ( object ) ;
}
let id = 0 ;
/ * *
* The minimum height for the Jitsi Meet frame
* @ type { number }
* /
const MIN _HEIGHT = 300 ;
/ * *
* The minimum width for the Jitsi Meet frame
* @ type { number }
* /
const MIN _WIDTH = 790 ;
/ * *
* Adds given number to the numberOfParticipants property of given APIInstance .
* @ param { JitsiMeetExternalAPI } APIInstance the instance of the
* JitsiMeetExternalAPI
* @ param { int } number - the number of participants to be added to
*
* @ param { JitsiMeetExternalAPI } APIInstance - The instance of the API .
* @ param { int } number - T he number of participants to be added to
* numberOfParticipants property ( this parameter can be negative number if the
* numberOfParticipants should be decreased ) .
* @ returns { void }
* /
function changeParticipantNumber ( APIInstance , number ) {
APIInstance . numberOfParticipants += number ;
@ -80,179 +70,206 @@ function changeParticipantNumber(APIInstance, number) {
* Generates array with URL params based on the passed config object that will
* be used for the Jitsi Meet URL generation .
*
* @ param config { object } t he config object .
* @ returns { Array < string > } t he array with URL param strings .
* @ param { Object } config - T he config object .
* @ returns { Array < string > } T he array with URL param strings .
* /
function configToURLParamsArray ( config ) {
function configToURLParamsArray ( config = { } ) {
const params = [ ] ;
for ( const key in config ) {
for ( const key in config ) { // eslint-disable-line guard-for-in
try {
params . push ( key + '='
+ encodeURIComponent ( JSON . stringify ( config [ key ] ) ) ) ;
params . push ( ` ${ key } = ${
encodeURIComponent ( JSON . stringify ( config [ key ] ) ) } ` );
} catch ( e ) {
console . warn ( ` Error encoding ${ key } : ${ e } ` ) ;
}
}
return params ;
}
/ * *
* Generates the URL for the iframe .
*
* @ param { string } domain - The domain name of the server that hosts the
* conference .
* @ param { string } [ options ] - Another optional parameters .
* @ param { Object } [ options . configOverwrite ] - Object containing configuration
* options defined in config . js to be overridden .
* @ param { Object } [ options . interfaceConfigOverwrite ] - Object containing
* configuration options defined in interface _config . js to be overridden .
* @ param { string } [ options . jwt ] - The JWT token if needed by jitsi - meet for
* authentication .
* @ param { boolean } [ options . noSsl ] - If the value is true https won ' t be used .
* @ param { string } [ options . roomName ] - The name of the room to join .
* @ returns { string } The URL .
* /
function generateURL ( domain , options = { } ) {
const {
configOverwrite ,
interfaceConfigOverwrite ,
jwt ,
noSSL ,
roomName
} = options ;
let url = ` ${ noSSL ? 'http' : 'https' } :// ${ domain } / ${ roomName || '' } ` ;
if ( jwt ) {
url += ` ?jwt= ${ jwt } ` ;
}
url += ` #jitsi_meet_external_api_id= ${ id } ` ;
const configURLParams = configToURLParamsArray ( configOverwrite ) ;
if ( configURLParams . length ) {
url += ` &config. ${ configURLParams . join ( '&config.' ) } ` ;
}
const interfaceConfigURLParams
= configToURLParamsArray ( interfaceConfigOverwrite ) ;
if ( interfaceConfigURLParams . length ) {
url += ` &interfaceConfig. ${
interfaceConfigURLParams . join ( '&interfaceConfig.' ) } ` ;
}
return url ;
}
/ * *
* The IFrame API interface class .
* /
class JitsiMeetExternalAPI extends EventEmitter {
/ * *
* 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 configOverwrite object containing configuration options defined in
* config . js to be overridden .
* @ param interfaceConfigOverwrite object containing configuration options
* defined in interface _config . js to be overridden .
* @ param noSsl if the value is true https won ' t be used
* @ param { string } [ jwt ] the JWT token if needed by jitsi - meet for
* Constructs new API instance . Creates iframe and loads Jitsi Meet in it .
*
* @ param { string } domain - The domain name of the server that hosts the
* conference .
* @ param { string } [ roomName ] - The name of the room to join .
* @ param { number } [ width ] - Width of the iframe .
* @ param { number } [ height ] - Height of the iframe .
* @ param { DOMElement } [ parentNode ] - The node that will contain the
* iframe .
* @ param { Object } [ configOverwrite ] - Object containing configuration
* options defined in config . js to be overridden .
* @ param { Object } [ interfaceConfigOverwrite ] - Object containing
* configuration options defined in interface _config . js to be overridden .
* @ param { boolean } [ noSSL ] - If the value is true https won ' t be used .
* @ param { string } [ jwt ] - The JWT token if needed by jitsi - meet for
* authentication .
* @ constructor
* /
constructor ( domain , room _name , width , height , parentNode ,
configOverwrite , interfaceConfigOverwrite , noSsl , jwt ) {
constructor ( domain , // eslint-disable-line max-params
roomName = '' ,
width = MIN _WIDTH ,
height = MIN _HEIGHT ,
parentNode = document . body ,
configOverwrite = { } ,
interfaceConfigOverwrite = { } ,
noSSL = false ,
jwt = undefined ) {
super ( ) ;
this . parentNode = parentNode ;
this . url = generateURL ( domain , {
configOverwrite ,
interfaceConfigOverwrite ,
jwt ,
noSSL ,
roomName
} ) ;
this . _createIFrame ( Math . max ( height , MIN _HEIGHT ) ,
Math . max ( width , MIN _WIDTH ) ) ;
this . postis = postisInit ( {
scope : ` jitsi_meet_external_api_ ${ id } ` ,
window : this . frame . contentWindow
} ) ;
this . numberOfParticipants = 1 ;
this . _setupListeners ( ) ;
id ++ ;
}
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 ;
}
if ( jwt ) {
this . url += '?jwt=' + jwt ;
}
this . url += "#jitsi_meet_external_api_id=" + id ;
const configURLParams = configToURLParamsArray ( configOverwrite ) ;
if ( configURLParams . length ) {
this . url += '&config.' + configURLParams . join ( '&config.' ) ;
}
/ * *
* Creates the iframe element .
*
* @ param { number } height - The height of the iframe .
* @ param { number } width - The with of the iframe .
* @ returns { void }
*
* @ private
* /
_createIFrame ( height , width ) {
this . iframeHolder
= this . parentNode . appendChild ( document . createElement ( 'div' ) ) ;
this . iframeHolder . id = ` jitsiConference ${ id } ` ;
this . iframeHolder . style . width = ` ${ width } px ` ;
this . iframeHolder . style . height = ` ${ height } px ` ;
const interfaceConfigURLParams
= configToURLParamsArray ( interfaceConfigOverwrite ) ;
if ( interfaceConfigURLParams . length ) {
this . url += '&interfaceConfig.'
+ interfaceConfigURLParams . join ( '&interfaceConfig.' ) ;
}
this . frameName = ` jitsiConferenceFrame ${ id } ` ;
this . frame = document . createElement ( "iframe" ) ;
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 . 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 = { } ;
// Map<{string} event_name, {boolean} postis_listener_added>
this . postisListeners = { } ;
this . numberOfParticipants = 1 ;
this . _setupListeners ( ) ;
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
* Setups listeners that are used internally for JitsiMeetExternalAPI .
*
* @ returns { void }
*
* @ private
* /
executeCommand ( name , ... argumentsList ) {
if ( ! ( name in commands ) ) {
logger . error ( "Not supported command name." ) ;
return ;
_setupListeners ( ) {
this . postis . listen ( 'participant-joined' ,
changeParticipantNumber . bind ( null , this , 1 ) ) ;
this . postis . listen ( 'participant-left' ,
changeParticipantNumber . bind ( null , this , - 1 ) ) ;
for ( const eventName in events ) { // eslint-disable-line guard-for-in
const postisMethod = events [ eventName ] ;
this . postis . listen ( postisMethod ,
( ... args ) => this . emit ( eventName , ... args ) ) ;
}
sendMessage ( this . postis , {
method : commands [ name ] ,
params : argumentsList
} ) ;
}
/ * *
* 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 .
* Adds event listener to Meet Jitsi .
*
* @ param { string } event - The name of the event .
* @ param { Function } listener - The listener .
* @ returns { void }
*
* @ deprecated
* NOTE : This method is not removed for backward comatability purposes .
* /
executeCommands ( object ) {
for ( var key in object ) {
this . executeCommand ( key , object [ key ] ) ;
}
addEventListener ( event , listener ) {
this . on ( event , listener ) ;
}
/ * *
* Adds event listeners to Meet Jitsi . The object key should be the name of
* Adds event listeners to Meet Jitsi .
*
* @ param { Object } listeners - 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
* '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
* 'message' : txt //the text of the message
* } }
* displayNameChanged - receives event notifications about display name
* change . The listener will receive object with the following structure :
@ -285,126 +302,116 @@ class JitsiMeetExternalAPI extends EventEmitter {
* } }
* readyToClose - all hangup operations are completed and Jitsi Meet is
* ready to be disposed .
* @ param object
* @ returns { void }
*
* @ deprecated
* NOTE : This method is not removed for backward comatability purposes .
* /
addEventListeners ( object ) {
for ( var i in object ) {
this . addEventListener ( i , object [ i ] ) ;
addEventListeners ( listeners ) {
for ( const event in listeners ) { // eslint-disable-line guard-for-in
this . addEventListener ( event , listeners [ event ] ) ;
}
}
/ * *
* 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
* Removes the listeners and removes the Jitsi Meet frame .
*
* NOTE : This method is not removed for backward comatability purposes .
* @ returns { void }
* /
addEventListener ( event , listener ) {
this . on ( event , listener ) ;
dispose ( ) {
const frame = document . getElementById ( this . frameName ) ;
this . postis . destroy ( ) ;
if ( frame ) {
frame . src = 'about:blank' ;
}
window . setTimeout ( ( ) => {
this . iframeHolder . removeChild ( this . frame ) ;
this . iframeHolder . parentNode . removeChild ( this . iframeHolder ) ;
} , 10 ) ;
}
/ * *
* Removes event listener .
* @ param event the name of the event .
* NOTE : This method is not removed for backward comatability purposes .
* 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 { string } name - The name of the command .
* @ returns { void }
* /
removeEventListener ( event ) {
this . removeListeners ( event ) ;
executeCommand ( name , ... args ) {
if ( ! ( name in commands ) ) {
logger . error ( 'Not supported command name.' ) ;
return ;
}
this . postis . send ( {
method : commands [ name ] ,
params : args
} ) ;
}
/ * *
* Removes event listeners .
* @ param events array with the names of the events .
* NOTE : This method is not removed for backward comatability purposes .
* 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 } commandList - 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 .
* @ returns { void }
* /
removeEventListeners ( events ) {
for ( var i = 0 ; i < events . length ; i ++ ) {
this . removeEventListener ( events [ i ] ) ;
executeCommands ( commandList ) {
for ( const key in commandList ) { // eslint-disable-line guard-for-in
this . executeCommand ( key , commandList [ key ] ) ;
}
}
/ * *
* Returns the number of participants in the conference .
* NOTE : the local participant is included .
* @ returns { int } the number of participants in the conference .
* Returns the number of participants in the conference . The local
* participant is included .
*
* @ returns { int } The number of participants in the conference .
* /
getNumberOfParticipants ( ) {
return this . numberOfParticipants ;
}
/ * *
* Setups listeners that are used internally for JitsiMeetExternalAPI .
* Removes event listener .
*
* @ param { string } event - The name of the event .
* @ returns { void }
*
* @ deprecated
* NOTE : This method is not removed for backward comatability purposes .
* /
_setupListeners ( ) {
this . postis . listen ( "participant-joined" ,
changeParticipantNumber . bind ( null , this , 1 ) ) ;
this . postis . listen ( "participant-left" ,
changeParticipantNumber . bind ( null , this , - 1 ) ) ;
for ( const eventName in events ) {
const postisMethod = events [ eventName ] ;
this . postis . listen ( postisMethod ,
( ... args ) => this . emit ( eventName , ... args ) ) ;
}
removeEventListener ( event ) {
this . removeListeners ( event ) ;
}
/ * *
* Removes the listeners and removes the Jitsi Meet frame .
* Removes event listeners .
*
* @ param { Array < string > } eventList - Array with the names of the events .
* @ returns { void }
*
* @ deprecated
* NOTE : This method is not removed for backward comatability purposes .
* /
dispose ( ) {
this . postis . destroy ( ) ;
var frame = document . getElementById ( this . frameName ) ;
if ( frame )
frame . src = 'about:blank' ;
window . setTimeout ( ( ) => {
this . iframeHolder . removeChild ( this . frame ) ;
this . iframeHolder . parentNode . removeChild ( this . iframeHolder ) ;
} , 10 ) ;
removeEventListeners ( eventList ) {
eventList . forEach ( event => this . removeEventListener ( event ) ) ;
}
}