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.

UI.js 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. var UI = {};
  2. var VideoLayout = require("./videolayout/VideoLayout.js");
  3. var AudioLevels = require("./audio_levels/AudioLevels.js");
  4. var Prezi = require("./prezi/Prezi.js");
  5. var Etherpad = require("./etherpad/Etherpad.js");
  6. var Chat = require("./side_pannels/chat/Chat.js");
  7. var Toolbar = require("./toolbars/Toolbar");
  8. var ToolbarToggler = require("./toolbars/ToolbarToggler");
  9. var BottomToolbar = require("./toolbars/BottomToolbar");
  10. var ContactList = require("./side_pannels/contactlist/ContactList");
  11. var Avatar = require("./avatar/Avatar");
  12. var EventEmitter = require("events");
  13. var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
  14. var Settings = require("./side_pannels/settings/Settings");
  15. var PanelToggler = require("./side_pannels/SidePanelToggler");
  16. var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
  17. UI.messageHandler = require("./util/MessageHandler");
  18. var messageHandler = UI.messageHandler;
  19. var Authentication = require("./authentication/Authentication");
  20. var UIUtil = require("./util/UIUtil");
  21. var NicknameHandler = require("./util/NicknameHandler");
  22. var eventEmitter = new EventEmitter();
  23. var roomName = null;
  24. function setupPrezi()
  25. {
  26. $("#reloadPresentationLink").click(function()
  27. {
  28. Prezi.reloadPresentation();
  29. });
  30. }
  31. function setupChat()
  32. {
  33. Chat.init();
  34. $("#toggle_smileys").click(function() {
  35. Chat.toggleSmileys();
  36. });
  37. }
  38. function setupToolbars() {
  39. Toolbar.init(UI);
  40. Toolbar.setupButtonsFromConfig();
  41. BottomToolbar.init();
  42. }
  43. function streamHandler(stream) {
  44. switch (stream.type)
  45. {
  46. case "audio":
  47. VideoLayout.changeLocalAudio(stream);
  48. break;
  49. case "video":
  50. VideoLayout.changeLocalVideo(stream);
  51. break;
  52. case "stream":
  53. VideoLayout.changeLocalStream(stream);
  54. break;
  55. }
  56. }
  57. function onDisposeConference(unload) {
  58. Toolbar.showAuthenticateButton(false);
  59. };
  60. function onDisplayNameChanged(jid, displayName) {
  61. ContactList.onDisplayNameChange(jid, displayName);
  62. SettingsMenu.onDisplayNameChange(jid, displayName);
  63. VideoLayout.onDisplayNameChanged(jid, displayName);
  64. }
  65. function registerListeners() {
  66. RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  67. RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
  68. RTC.addStreamListener(function (stream) {
  69. VideoLayout.onRemoteStreamAdded(stream);
  70. }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
  71. VideoLayout.init();
  72. statistics.addAudioLevelListener(function(jid, audioLevel)
  73. {
  74. var resourceJid;
  75. if(jid === statistics.LOCAL_JID)
  76. {
  77. resourceJid = AudioLevels.LOCAL_LEVEL;
  78. if(RTC.localAudio.isMuted())
  79. {
  80. audioLevel = 0;
  81. }
  82. }
  83. else
  84. {
  85. resourceJid = Strophe.getResourceFromJid(jid);
  86. }
  87. AudioLevels.updateAudioLevel(resourceJid, audioLevel,
  88. UI.getLargeVideoState().userResourceJid);
  89. });
  90. desktopsharing.addListener(function () {
  91. ToolbarToggler.showDesktopSharingButton();
  92. }, DesktopSharingEventTypes.INIT);
  93. desktopsharing.addListener(
  94. Toolbar.changeDesktopSharingButtonState,
  95. DesktopSharingEventTypes.SWITCHING_DONE);
  96. xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
  97. xmpp.addListener(XMPPEvents.KICKED, function () {
  98. messageHandler.openMessageDialog("Session Terminated",
  99. "Ouch! You have been kicked out of the meet!");
  100. });
  101. xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
  102. messageHandler.showError("Error",
  103. "Jitsi Videobridge is currently unavailable. Please try again later!");
  104. });
  105. xmpp.addListener(XMPPEvents.USER_ID_CHANGED, Avatar.setUserAvatar);
  106. xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
  107. for(stream in changedStreams)
  108. {
  109. // might need to update the direction if participant just went from sendrecv to recvonly
  110. if (stream.type === 'video' || stream.type === 'screen') {
  111. var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>video');
  112. switch (stream.direction) {
  113. case 'sendrecv':
  114. el.show();
  115. break;
  116. case 'recvonly':
  117. el.hide();
  118. // FIXME: Check if we have to change large video
  119. //VideoLayout.updateLargeVideo(el);
  120. break;
  121. }
  122. }
  123. }
  124. });
  125. xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
  126. xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
  127. xmpp.addListener(XMPPEvents.LOCALROLE_CHANGED, onLocalRoleChange);
  128. xmpp.addListener(XMPPEvents.MUC_ENTER, onMucEntered);
  129. xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
  130. xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
  131. xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
  132. xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
  133. xmpp.addListener(XMPPEvents.MUC_LEFT, onMucLeft);
  134. xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordReqiured);
  135. xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
  136. xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
  137. }
  138. function bindEvents()
  139. {
  140. /**
  141. * Resizes and repositions videos in full screen mode.
  142. */
  143. $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
  144. function () {
  145. VideoLayout.resizeLargeVideoContainer();
  146. VideoLayout.positionLarge();
  147. }
  148. );
  149. $(window).resize(function () {
  150. VideoLayout.resizeLargeVideoContainer();
  151. VideoLayout.positionLarge();
  152. });
  153. }
  154. UI.start = function () {
  155. document.title = interfaceConfig.APP_NAME;
  156. if(config.enableWelcomePage && window.location.pathname == "/" &&
  157. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  158. {
  159. $("#videoconference_page").hide();
  160. var setupWelcomePage = require("./welcome_page/WelcomePage");
  161. setupWelcomePage();
  162. return;
  163. }
  164. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  165. var leftWatermarkDiv
  166. = $("#largeVideoContainer div[class='watermark leftwatermark']");
  167. leftWatermarkDiv.css({display: 'block'});
  168. leftWatermarkDiv.parent().get(0).href
  169. = interfaceConfig.JITSI_WATERMARK_LINK;
  170. }
  171. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  172. var rightWatermarkDiv
  173. = $("#largeVideoContainer div[class='watermark rightwatermark']");
  174. rightWatermarkDiv.css({display: 'block'});
  175. rightWatermarkDiv.parent().get(0).href
  176. = interfaceConfig.BRAND_WATERMARK_LINK;
  177. rightWatermarkDiv.get(0).style.backgroundImage
  178. = "url(images/rightwatermark.png)";
  179. }
  180. if (interfaceConfig.SHOW_POWERED_BY) {
  181. $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
  182. }
  183. $("#welcome_page").hide();
  184. $('body').popover({ selector: '[data-toggle=popover]',
  185. trigger: 'click hover',
  186. content: function() {
  187. return this.getAttribute("content") +
  188. keyboardshortcut.getShortcut(this.getAttribute("shortcut"));
  189. }
  190. });
  191. VideoLayout.resizeLargeVideoContainer();
  192. $("#videospace").mousemove(function () {
  193. return ToolbarToggler.showToolbar();
  194. });
  195. // Set the defaults for prompt dialogs.
  196. jQuery.prompt.setDefaults({persistent: false});
  197. NicknameHandler.init(eventEmitter);
  198. registerListeners();
  199. bindEvents();
  200. setupPrezi();
  201. setupToolbars();
  202. setupChat();
  203. document.title = interfaceConfig.APP_NAME;
  204. $("#downloadlog").click(function (event) {
  205. dump(event.target);
  206. });
  207. if(config.enableWelcomePage && window.location.pathname == "/" &&
  208. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  209. {
  210. $("#videoconference_page").hide();
  211. var setupWelcomePage = require("./welcome_page/WelcomePage");
  212. setupWelcomePage();
  213. return;
  214. }
  215. $("#welcome_page").hide();
  216. document.getElementById('largeVideo').volume = 0;
  217. if (!$('#settings').is(':visible')) {
  218. console.log('init');
  219. init();
  220. } else {
  221. loginInfo.onsubmit = function (e) {
  222. if (e.preventDefault) e.preventDefault();
  223. $('#settings').hide();
  224. init();
  225. };
  226. }
  227. toastr.options = {
  228. "closeButton": true,
  229. "debug": false,
  230. "positionClass": "notification-bottom-right",
  231. "onclick": null,
  232. "showDuration": "300",
  233. "hideDuration": "1000",
  234. "timeOut": "2000",
  235. "extendedTimeOut": "1000",
  236. "showEasing": "swing",
  237. "hideEasing": "linear",
  238. "showMethod": "fadeIn",
  239. "hideMethod": "fadeOut",
  240. "reposition": function() {
  241. if(PanelToggler.isVisible()) {
  242. $("#toast-container").addClass("notification-bottom-right-center");
  243. } else {
  244. $("#toast-container").removeClass("notification-bottom-right-center");
  245. }
  246. },
  247. "newestOnTop": false
  248. };
  249. $('#settingsmenu>input').keyup(function(event){
  250. if(event.keyCode === 13) {//enter
  251. SettingsMenu.update();
  252. }
  253. });
  254. $("#updateSettings").click(function () {
  255. SettingsMenu.update();
  256. });
  257. };
  258. UI.toggleSmileys = function () {
  259. Chat.toggleSmileys();
  260. };
  261. function chatAddError(errorMessage, originalText)
  262. {
  263. return Chat.chatAddError(errorMessage, originalText);
  264. };
  265. function chatSetSubject(text)
  266. {
  267. return Chat.chatSetSubject(text);
  268. };
  269. function updateChatConversation(from, displayName, message) {
  270. return Chat.updateChatConversation(from, displayName, message);
  271. };
  272. function onMucJoined(jid, info) {
  273. Toolbar.updateRoomUrl(window.location.href);
  274. document.getElementById('localNick').appendChild(
  275. document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
  276. );
  277. var settings = Settings.getSettings();
  278. // Add myself to the contact list.
  279. ContactList.addContact(jid, settings.email || settings.uid);
  280. // Once we've joined the muc show the toolbar
  281. ToolbarToggler.showToolbar();
  282. // Show authenticate button if needed
  283. Toolbar.showAuthenticateButton(
  284. xmpp.isExternalAuthEnabled() && !xmpp.isModerator());
  285. var displayName = !config.displayJids
  286. ? info.displayName : Strophe.getResourceFromJid(jid);
  287. if (displayName)
  288. onDisplayNameChanged('localVideoContainer', displayName + ' (me)');
  289. }
  290. function initEtherpad(name) {
  291. Etherpad.init(name);
  292. };
  293. function onMucLeft(jid) {
  294. console.log('left.muc', jid);
  295. var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
  296. '>.displayname').html();
  297. messageHandler.notify(displayName || 'Somebody',
  298. 'disconnected',
  299. 'disconnected');
  300. // Need to call this with a slight delay, otherwise the element couldn't be
  301. // found for some reason.
  302. // XXX(gp) it works fine without the timeout for me (with Chrome 38).
  303. window.setTimeout(function () {
  304. var container = document.getElementById(
  305. 'participant_' + Strophe.getResourceFromJid(jid));
  306. if (container) {
  307. ContactList.removeContact(jid);
  308. VideoLayout.removeConnectionIndicator(jid);
  309. // hide here, wait for video to close before removing
  310. $(container).hide();
  311. VideoLayout.resizeThumbnails();
  312. }
  313. }, 10);
  314. VideoLayout.participantLeft(jid);
  315. };
  316. UI.getSettings = function () {
  317. return Settings.getSettings();
  318. };
  319. UI.toggleFilmStrip = function () {
  320. return BottomToolbar.toggleFilmStrip();
  321. };
  322. UI.toggleChat = function () {
  323. return BottomToolbar.toggleChat();
  324. };
  325. UI.toggleContactList = function () {
  326. return BottomToolbar.toggleContactList();
  327. };
  328. function onLocalRoleChange(jid, info, pres, isModerator, isExternalAuthEnabled)
  329. {
  330. console.info("My role changed, new role: " + info.role);
  331. onModeratorStatusChanged(isModerator);
  332. VideoLayout.showModeratorIndicator();
  333. Toolbar.showAuthenticateButton(
  334. isExternalAuthEnabled && !isModerator);
  335. if (isModerator) {
  336. Authentication.closeAuthenticationWindow();
  337. messageHandler.notify(
  338. 'Me', 'connected', 'Moderator rights granted !');
  339. }
  340. }
  341. function onModeratorStatusChanged(isModerator) {
  342. Toolbar.showSipCallButton(isModerator);
  343. Toolbar.showRecordingButton(
  344. isModerator); //&&
  345. // FIXME:
  346. // Recording visible if
  347. // there are at least 2(+ 1 focus) participants
  348. //Object.keys(connection.emuc.members).length >= 3);
  349. if (isModerator && config.etherpad_base) {
  350. Etherpad.init();
  351. }
  352. };
  353. function onPasswordReqiured(callback) {
  354. // password is required
  355. Toolbar.lockLockButton();
  356. messageHandler.openTwoButtonDialog(null,
  357. '<h2>Password required</h2>' +
  358. '<input id="lockKey" type="text" placeholder="password" autofocus>',
  359. true,
  360. "Ok",
  361. function (e, v, m, f) {},
  362. function (event) {
  363. document.getElementById('lockKey').focus();
  364. },
  365. function (e, v, m, f) {
  366. if (v) {
  367. var lockKey = document.getElementById('lockKey');
  368. if (lockKey.value !== null) {
  369. Toolbar.setSharedKey(lockKey.value);
  370. callback(lockKey.value);
  371. }
  372. }
  373. }
  374. );
  375. }
  376. function onMucEntered(jid, id, displayName) {
  377. messageHandler.notify(displayName || 'Somebody',
  378. 'connected',
  379. 'connected');
  380. // Add Peer's container
  381. VideoLayout.ensurePeerContainerExists(jid,id);
  382. }
  383. function onMucPresenceStatus( jid, info) {
  384. VideoLayout.setPresenceStatus(
  385. 'participant_' + Strophe.getResourceFromJid(jid), info.status);
  386. }
  387. function onMucRoleChanged(role, displayName) {
  388. VideoLayout.showModeratorIndicator();
  389. if (role === 'moderator') {
  390. var displayName = displayName;
  391. if (!displayName) {
  392. displayName = 'Somebody';
  393. }
  394. messageHandler.notify(
  395. displayName,
  396. 'connected',
  397. 'Moderator rights granted to ' + displayName + '!');
  398. }
  399. }
  400. UI.onAuthenticationRequired = function (intervalCallback) {
  401. Authentication.openAuthenticationDialog(
  402. roomName, intervalCallback, function () {
  403. Toolbar.authenticateClicked();
  404. });
  405. };
  406. UI.setRecordingButtonState = function (state) {
  407. Toolbar.setRecordingButtonState(state);
  408. };
  409. UI.inputDisplayNameHandler = function (value) {
  410. VideoLayout.inputDisplayNameHandler(value);
  411. };
  412. UI.updateLocalConnectionStats = function(percent, stats)
  413. {
  414. VideoLayout.updateLocalConnectionStats(percent, stats);
  415. };
  416. UI.updateConnectionStats = function(jid, percent, stats)
  417. {
  418. VideoLayout.updateConnectionStats(jid, percent, stats);
  419. };
  420. UI.onStatsStop = function () {
  421. VideoLayout.onStatsStop();
  422. };
  423. UI.getLargeVideoState = function()
  424. {
  425. return VideoLayout.getLargeVideoState();
  426. };
  427. UI.showLocalAudioIndicator = function (mute) {
  428. VideoLayout.showLocalAudioIndicator(mute);
  429. };
  430. UI.generateRoomName = function() {
  431. if(roomName)
  432. return roomName;
  433. var roomnode = null;
  434. var path = window.location.pathname;
  435. // determinde the room node from the url
  436. // TODO: just the roomnode or the whole bare jid?
  437. if (config.getroomnode && typeof config.getroomnode === 'function') {
  438. // custom function might be responsible for doing the pushstate
  439. roomnode = config.getroomnode(path);
  440. } else {
  441. /* fall back to default strategy
  442. * this is making assumptions about how the URL->room mapping happens.
  443. * It currently assumes deployment at root, with a rewrite like the
  444. * following one (for nginx):
  445. location ~ ^/([a-zA-Z0-9]+)$ {
  446. rewrite ^/(.*)$ / break;
  447. }
  448. */
  449. if (path.length > 1) {
  450. roomnode = path.substr(1).toLowerCase();
  451. } else {
  452. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  453. roomnode = word.toLowerCase();
  454. window.history.pushState('VideoChat',
  455. 'Room: ' + word, window.location.pathname + word);
  456. }
  457. }
  458. roomName = roomnode + '@' + config.hosts.muc;
  459. return roomName;
  460. };
  461. UI.connectionIndicatorShowMore = function(id)
  462. {
  463. return VideoLayout.connectionIndicators[id].showMore();
  464. };
  465. UI.showToolbar = function () {
  466. return ToolbarToggler.showToolbar();
  467. };
  468. UI.dockToolbar = function (isDock) {
  469. return ToolbarToggler.dockToolbar(isDock);
  470. };
  471. UI.getCreadentials = function () {
  472. return {
  473. bosh: document.getElementById('boshURL').value,
  474. password: document.getElementById('password').value,
  475. jid: document.getElementById('jid').value
  476. };
  477. };
  478. UI.disableConnect = function () {
  479. document.getElementById('connect').disabled = true;
  480. };
  481. UI.showLoginPopup = function(callback)
  482. {
  483. console.log('password is required');
  484. UI.messageHandler.openTwoButtonDialog(null,
  485. '<h2>Password required</h2>' +
  486. '<input id="passwordrequired.username" type="text" placeholder="user@domain.net" autofocus>' +
  487. '<input id="passwordrequired.password" type="password" placeholder="user password">',
  488. true,
  489. "Ok",
  490. function (e, v, m, f) {
  491. if (v) {
  492. var username = document.getElementById('passwordrequired.username');
  493. var password = document.getElementById('passwordrequired.password');
  494. if (username.value !== null && password.value != null) {
  495. callback(username.value, password.value);
  496. }
  497. }
  498. },
  499. function (event) {
  500. document.getElementById('passwordrequired.username').focus();
  501. }
  502. );
  503. }
  504. UI.checkForNicknameAndJoin = function () {
  505. Authentication.closeAuthenticationDialog();
  506. Authentication.stopInterval();
  507. var nick = null;
  508. if (config.useNicks) {
  509. nick = window.prompt('Your nickname (optional)');
  510. }
  511. xmpp.joinRoom(roomName, config.useNicks, nick);
  512. }
  513. function dump(elem, filename) {
  514. elem = elem.parentNode;
  515. elem.download = filename || 'meetlog.json';
  516. elem.href = 'data:application/json;charset=utf-8,\n';
  517. var data = xmpp.populateData();
  518. var metadata = {};
  519. metadata.time = new Date();
  520. metadata.url = window.location.href;
  521. metadata.ua = navigator.userAgent;
  522. var log = xmpp.getLogger();
  523. if (log) {
  524. metadata.xmpp = log;
  525. }
  526. data.metadata = metadata;
  527. elem.href += encodeURIComponent(JSON.stringify(data, null, ' '));
  528. return false;
  529. }
  530. UI.getRoomName = function () {
  531. return roomName;
  532. }
  533. /**
  534. * Mutes/unmutes the local video.
  535. *
  536. * @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
  537. * @param options an object which specifies optional arguments such as the
  538. * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
  539. * specifies whether the method was initiated in response to a user command (in
  540. * contrast to an automatic decision taken by the application logic)
  541. */
  542. function setVideoMute(mute, options) {
  543. xmpp.setVideoMute(
  544. mute,
  545. function (mute) {
  546. var video = $('#video');
  547. var communicativeClass = "icon-camera";
  548. var muteClass = "icon-camera icon-camera-disabled";
  549. if (mute) {
  550. video.removeClass(communicativeClass);
  551. video.addClass(muteClass);
  552. } else {
  553. video.removeClass(muteClass);
  554. video.addClass(communicativeClass);
  555. }
  556. },
  557. options);
  558. }
  559. /**
  560. * Mutes/unmutes the local video.
  561. */
  562. UI.toggleVideo = function () {
  563. UIUtil.buttonClick("#video", "icon-camera icon-camera-disabled");
  564. setVideoMute(!RTC.localVideo.isMuted());
  565. };
  566. /**
  567. * Mutes / unmutes audio for the local participant.
  568. */
  569. UI.toggleAudio = function() {
  570. UI.setAudioMuted(!RTC.localAudio.isMuted());
  571. };
  572. /**
  573. * Sets muted audio state for the local participant.
  574. */
  575. UI.setAudioMuted = function (mute) {
  576. if(!xmpp.setAudioMute(mute, function () {
  577. UI.showLocalAudioIndicator(mute);
  578. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  579. }))
  580. {
  581. // We still click the button.
  582. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  583. return;
  584. }
  585. }
  586. UI.onLastNChanged = function (oldValue, newValue) {
  587. if (config.muteLocalVideoIfNotInLastN) {
  588. setVideoMute(!newValue, { 'byUser': false });
  589. }
  590. }
  591. UI.addListener = function (type, listener) {
  592. eventEmitter.on(type, listener);
  593. }
  594. UI.clickOnVideo = function (videoNumber) {
  595. var remoteVideos = $(".videocontainer:not(#mixedstream)");
  596. if (remoteVideos.length > videoNumber) {
  597. remoteVideos[videoNumber].click();
  598. }
  599. }
  600. module.exports = UI;