You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

API.js 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
  2. import { parseJWTFromURLParams } from '../../react/features/jwt';
  3. import { getJitsiMeetTransport } from '../transport';
  4. import { API_ID } from './constants';
  5. declare var APP: Object;
  6. /**
  7. * List of the available commands.
  8. */
  9. let commands = {};
  10. /**
  11. * The state of screen sharing(started/stopped) before the screen sharing is
  12. * enabled and initialized.
  13. * NOTE: This flag help us to cache the state and use it if toggle-share-screen
  14. * was received before the initialization.
  15. */
  16. let initialScreenSharingState = false;
  17. /**
  18. * The transport instance used for communication with external apps.
  19. *
  20. * @type {Transport}
  21. */
  22. const transport = getJitsiMeetTransport();
  23. /**
  24. * The current audio availability.
  25. *
  26. * @type {boolean}
  27. */
  28. let audioAvailable = true;
  29. /**
  30. * The current video availability.
  31. *
  32. * @type {boolean}
  33. */
  34. let videoAvailable = true;
  35. /**
  36. * Initializes supported commands.
  37. *
  38. * @returns {void}
  39. */
  40. function initCommands() {
  41. commands = {
  42. 'display-name':
  43. APP.conference.changeLocalDisplayName.bind(APP.conference),
  44. 'toggle-audio': () => {
  45. APP.conference.toggleAudioMuted(false /* no UI */);
  46. },
  47. 'toggle-video': () => {
  48. APP.conference.toggleVideoMuted(false /* no UI */);
  49. },
  50. 'toggle-film-strip': APP.UI.toggleFilmstrip,
  51. 'toggle-chat': APP.UI.toggleChat,
  52. 'toggle-contact-list': APP.UI.toggleContactList,
  53. 'toggle-share-screen': toggleScreenSharing,
  54. 'video-hangup': () => APP.conference.hangup(),
  55. 'email': APP.conference.changeLocalEmail,
  56. 'avatar-url': APP.conference.changeLocalAvatarUrl
  57. };
  58. transport.on('event', ({ data, name }) => {
  59. if (name && commands[name]) {
  60. commands[name](...data);
  61. return true;
  62. }
  63. return false;
  64. });
  65. transport.on('request', ({ data, name }, callback) => {
  66. switch (name) {
  67. case 'is-audio-muted':
  68. callback(APP.conference.isLocalAudioMuted());
  69. break;
  70. case 'is-video-muted':
  71. callback(APP.conference.isLocalVideoMuted());
  72. break;
  73. case 'is-audio-available':
  74. callback(audioAvailable);
  75. break;
  76. case 'is-video-available':
  77. callback(videoAvailable);
  78. break;
  79. default:
  80. return false;
  81. }
  82. return true;
  83. });
  84. }
  85. /**
  86. * Listens for desktop/screen sharing enabled events and toggles the screen
  87. * sharing if needed.
  88. *
  89. * @param {boolean} enabled - Current screen sharing enabled status.
  90. * @returns {void}
  91. */
  92. function onDesktopSharingEnabledChanged(enabled = false) {
  93. if (enabled && initialScreenSharingState) {
  94. toggleScreenSharing();
  95. }
  96. }
  97. /**
  98. * Check whether the API should be enabled or not.
  99. *
  100. * @returns {boolean}
  101. */
  102. function shouldBeEnabled() {
  103. return (
  104. typeof API_ID === 'number'
  105. // XXX Enable the API when a JSON Web Token (JWT) is specified in
  106. // the location/URL because then it is very likely that the Jitsi
  107. // Meet (Web) app is being used by an external/wrapping (Web) app
  108. // and, consequently, the latter will need to communicate with the
  109. // former. (The described logic is merely a heuristic though.)
  110. || parseJWTFromURLParams());
  111. }
  112. /**
  113. * Executes on toggle-share-screen command.
  114. *
  115. * @returns {void}
  116. */
  117. function toggleScreenSharing() {
  118. if (APP.conference.isDesktopSharingEnabled) {
  119. // eslint-disable-next-line no-empty-function
  120. APP.conference.toggleScreenSharing().catch(() => {});
  121. } else {
  122. initialScreenSharingState = !initialScreenSharingState;
  123. }
  124. }
  125. /**
  126. * Implements API class that communicates with external API class and provides
  127. * interface to access Jitsi Meet features by external applications that embed
  128. * Jitsi Meet.
  129. */
  130. class API {
  131. /**
  132. * Initializes the API. Setups message event listeners that will receive
  133. * information from external applications that embed Jitsi Meet. It also
  134. * sends a message to the external application that API is initialized.
  135. *
  136. * @param {Object} options - Optional parameters.
  137. * @returns {void}
  138. */
  139. init() {
  140. if (!shouldBeEnabled()) {
  141. return;
  142. }
  143. /**
  144. * Current status (enabled/disabled) of API.
  145. *
  146. * @private
  147. * @type {boolean}
  148. */
  149. this._enabled = true;
  150. APP.conference.addListener(
  151. JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
  152. onDesktopSharingEnabledChanged);
  153. initCommands();
  154. }
  155. /**
  156. * Sends event to the external application.
  157. *
  158. * @param {Object} event - The event to be sent.
  159. * @returns {void}
  160. */
  161. _sendEvent(event = {}) {
  162. if (this._enabled) {
  163. transport.sendEvent(event);
  164. }
  165. }
  166. /**
  167. * Notify external application (if API is enabled) that message was sent.
  168. *
  169. * @param {string} message - Message body.
  170. * @returns {void}
  171. */
  172. notifySendingChatMessage(message) {
  173. this._sendEvent({
  174. name: 'outgoing-message',
  175. message
  176. });
  177. }
  178. /**
  179. * Notify external application (if API is enabled) that message was
  180. * received.
  181. *
  182. * @param {Object} options - Object with the message properties.
  183. * @returns {void}
  184. */
  185. notifyReceivedChatMessage({ body, id, nick, ts } = {}) {
  186. if (APP.conference.isLocalId(id)) {
  187. return;
  188. }
  189. this._sendEvent({
  190. name: 'incoming-message',
  191. from: id,
  192. message: body,
  193. nick,
  194. stamp: ts
  195. });
  196. }
  197. /**
  198. * Notify external application (if API is enabled) that user joined the
  199. * conference.
  200. *
  201. * @param {string} id - User id.
  202. * @returns {void}
  203. */
  204. notifyUserJoined(id) {
  205. this._sendEvent({
  206. name: 'participant-joined',
  207. id
  208. });
  209. }
  210. /**
  211. * Notify external application (if API is enabled) that user left the
  212. * conference.
  213. *
  214. * @param {string} id - User id.
  215. * @returns {void}
  216. */
  217. notifyUserLeft(id) {
  218. this._sendEvent({
  219. name: 'participant-left',
  220. id
  221. });
  222. }
  223. /**
  224. * Notify external application (if API is enabled) that user changed their
  225. * nickname.
  226. *
  227. * @param {string} id - User id.
  228. * @param {string} displayname - User nickname.
  229. * @returns {void}
  230. */
  231. notifyDisplayNameChanged(id, displayname) {
  232. this._sendEvent({
  233. name: 'display-name-change',
  234. displayname,
  235. id
  236. });
  237. }
  238. /**
  239. * Notify external application (if API is enabled) that the conference has
  240. * been joined.
  241. *
  242. * @param {string} roomName - The room name.
  243. * @returns {void}
  244. */
  245. notifyConferenceJoined(roomName) {
  246. this._sendEvent({
  247. name: 'video-conference-joined',
  248. roomName
  249. });
  250. }
  251. /**
  252. * Notify external application (if API is enabled) that user changed their
  253. * nickname.
  254. *
  255. * @param {string} roomName - User id.
  256. * @returns {void}
  257. */
  258. notifyConferenceLeft(roomName) {
  259. this._sendEvent({
  260. name: 'video-conference-left',
  261. roomName
  262. });
  263. }
  264. /**
  265. * Notify external application (if API is enabled) that we are ready to be
  266. * closed.
  267. *
  268. * @returns {void}
  269. */
  270. notifyReadyToClose() {
  271. this._sendEvent({ name: 'video-ready-to-close' });
  272. }
  273. /**
  274. * Notify external application (if API is enabled) for audio muted status
  275. * changed.
  276. *
  277. * @param {boolean} muted - The new muted status.
  278. * @returns {void}
  279. */
  280. notifyAudioMutedStatusChanged(muted) {
  281. this._sendEvent({
  282. name: 'audio-mute-status-changed',
  283. muted
  284. });
  285. }
  286. /**
  287. * Notify external application (if API is enabled) for video muted status
  288. * changed.
  289. *
  290. * @param {boolean} muted - The new muted status.
  291. * @returns {void}
  292. */
  293. notifyVideoMutedStatusChanged(muted) {
  294. this._sendEvent({
  295. name: 'video-mute-status-changed',
  296. muted
  297. });
  298. }
  299. /**
  300. * Notify external application (if API is enabled) for audio availability
  301. * changed.
  302. *
  303. * @param {boolean} available - True if available and false otherwise.
  304. * @returns {void}
  305. */
  306. notifyAudioAvailabilityChanged(available) {
  307. audioAvailable = available;
  308. this._sendEvent({
  309. name: 'audio-availability-changed',
  310. available
  311. });
  312. }
  313. /**
  314. * Notify external application (if API is enabled) for video available
  315. * status changed.
  316. *
  317. * @param {boolean} available - True if available and false otherwise.
  318. * @returns {void}
  319. */
  320. notifyVideoAvailabilityChanged(available) {
  321. videoAvailable = available;
  322. this._sendEvent({
  323. name: 'video-availability-changed',
  324. available
  325. });
  326. }
  327. /**
  328. * Disposes the allocated resources.
  329. *
  330. * @returns {void}
  331. */
  332. dispose() {
  333. if (this._enabled) {
  334. this._enabled = false;
  335. APP.conference.removeListener(
  336. JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
  337. onDesktopSharingEnabledChanged);
  338. }
  339. }
  340. }
  341. export default new API();