From dbd68d2daa59a4107b0624615fa6f6592930b135 Mon Sep 17 00:00:00 2001 From: Boris Grozev Date: Fri, 31 Jul 2015 15:26:03 -0500 Subject: [PATCH] Updates app.bundle.js. --- index.html | 2 +- libs/app.bundle.js | 41672 +++++++++++++++++++++---------------------- 2 files changed, 20693 insertions(+), 20981 deletions(-) diff --git a/index.html b/index.html index 37269bc59a..110e4812f2 100644 --- a/index.html +++ b/index.html @@ -22,7 +22,7 @@ - + diff --git a/libs/app.bundle.js b/libs/app.bundle.js index 46adac2996..c52afc7b7a 100644 --- a/libs/app.bundle.js +++ b/libs/app.bundle.js @@ -1,20361 +1,19678 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.APP = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } + 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."); } - } +} - return this; -}; +/** + * Sends message to the external application. + * @param object + */ +function sendMessage(object) { + window.parent.postMessage(JSON.stringify(object), "*"); +} -EventEmitter.prototype.on = EventEmitter.prototype.addListener; +/** + * 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) {} -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + if(!message.type) + return; + switch (message.type) { + case "command": + processCommand(message); + break; + case "event": + processEvent(message); + break; + default: + console.error("Unknown type of the message"); + return; + } +} - var fired = false; +function setupListeners() { + APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, function (from) { + API.triggerEvent("participantJoined", {jid: from}); + }); + APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid, stamp) { + if (from != myjid) + API.triggerEvent("incomingMessage", + {"from": from, "nick": nick, "message": txt, "stamp": stamp}); + }); + APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, function (jid) { + API.triggerEvent("participantLeft", {jid: jid}); + }); + APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) { + var name = displayName[jid]; + if(!name || name != newDisplayName) { + API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName}); + displayName[jid] = newDisplayName; + } + }); + APP.xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) { + APP.API.triggerEvent("outgoingMessage", {"message": body}); + }); +} - function g() { - this.removeListener(type, g); +var API = { + /** + * Check whether the API should be enabled or not. + * @returns {boolean} + */ + isEnabled: function () { + var hash = location.hash; + if (hash && hash.indexOf("external") > -1 && window.postMessage) + return true; + return false; + }, + /** + * Initializes the APIConnector. Setups message event listeners that will + * receive information from external applications that embed Jitsi Meet. + * It also sends a message to the external application that APIConnector + * is initialized. + */ + init: function () { + initCommands(); + if (window.addEventListener) { + window.addEventListener('message', + processMessage, false); + } + else { + window.attachEvent('onmessage', processMessage); + } + sendMessage({type: "system", loaded: true}); + setupListeners(); + }, + /** + * Checks whether the event is enabled ot not. + * @param name the name of the event. + * @returns {*} + */ + isEventEnabled: function (name) { + return events[name]; + }, - if (!fired) { - fired = true; - listener.apply(this, arguments); + /** + * Sends event object to the external application that has been subscribed + * for that event. + * @param name the name event + * @param object data associated with the event + */ + triggerEvent: function (name, object) { + if(this.isEnabled() && this.isEventEnabled(name)) + sendMessage({ + type: "event", action: "result", event: name, result: object}); + }, + + /** + * Removes the listeners. + */ + dispose: function () { + if(window.removeEventListener) { + window.removeEventListener("message", + processMessage, false); + } + else { + window.detachEvent('onmessage', processMessage); + } } - } +}; - g.listener = listener; - this.on(type, g); +module.exports = API; +},{"../../service/xmpp/XMPPEvents":108}],3:[function(require,module,exports){ +/* global APP */ - return this; +/** + * A module for sending DTMF tones. + */ +var DTMFSender; +var initDtmfSender = function() { + // TODO: This needs to reset this if the peerconnection changes + // (e.g. the call is re-made) + if (DTMFSender) + return; + + var localAudio = APP.RTC.localAudio; + if (localAudio && localAudio.getTracks().length > 0) + { + var peerconnection + = APP.xmpp.getConnection().jingle.activecall.peerconnection; + if (peerconnection) { + DTMFSender = + peerconnection.peerconnection + .createDTMFSender(localAudio.getTracks()[0]); + console.log("Initialized DTMFSender"); + } + else { + console.log("Failed to initialize DTMFSender: no PeerConnection."); + } + } + else { + console.log("Failed to initialize DTMFSender: no audio track."); + } }; -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; +var DTMF = { + sendTones: function (tones, duration, pause) { + if (!DTMFSender) + initDtmfSender(); - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + if (DTMFSender){ + DTMFSender.insertDTMF(tones, + (duration || 200), + (pause || 200)); + } + } +}; - if (!this._events || !this._events[type]) - return this; +module.exports = DTMF; - list = this._events[type]; - length = list.length; - position = -1; - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); +},{}],4:[function(require,module,exports){ +/* global config, APP, Strophe */ - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } +// cache datachannels to avoid garbage collection +// https://code.google.com/p/chromium/issues/detail?id=405545 +var RTCEvents = require("../../service/RTC/RTCEvents"); - if (position < 0) - return this; +var _dataChannels = []; +var eventEmitter = null; - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } +var DataChannels = { + /** + * Callback triggered by PeerConnection when new data channel is opened + * on the bridge. + * @param event the event info object. + */ + onDataChannel: function (event) { + var dataChannel = event.channel; - return this; -}; + dataChannel.onopen = function () { + console.info("Data channel opened by the Videobridge!", dataChannel); -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; + // Code sample for sending string and/or binary data + // Sends String message to the bridge + //dataChannel.send("Hello bridge!"); + // Sends 12 bytes binary message to the bridge + //dataChannel.send(new ArrayBuffer(12)); - if (!this._events) - return this; + eventEmitter.emit(RTCEvents.DATA_CHANNEL_OPEN); + }; - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } + dataChannel.onerror = function (error) { + console.error("Data Channel Error:", error, dataChannel); + }; - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } + dataChannel.onmessage = function (event) { + var data = event.data; + // JSON + var obj; - listeners = this._events[type]; + try { + obj = JSON.parse(data); + } + catch (e) { + console.error( + "Failed to parse data channel message as JSON: ", + data, + dataChannel); + } + if (('undefined' !== typeof(obj)) && (null !== obj)) { + var colibriClass = obj.colibriClass; - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; + if ("DominantSpeakerEndpointChangeEvent" === colibriClass) { + // Endpoint ID from the Videobridge. + var dominantSpeakerEndpoint = obj.dominantSpeakerEndpoint; - return this; -}; + console.info( + "Data channel new dominant speaker event: ", + dominantSpeakerEndpoint); + eventEmitter.emit(RTCEvents.DOMINANTSPEAKER_CHANGED, dominantSpeakerEndpoint); + } + else if ("InLastNChangeEvent" === colibriClass) { + var oldValue = obj.oldValue; + var newValue = obj.newValue; + // Make sure that oldValue and newValue are of type boolean. + var type; + + if ((type = typeof oldValue) !== 'boolean') { + if (type === 'string') { + oldValue = (oldValue == "true"); + } else { + oldValue = new Boolean(oldValue).valueOf(); + } + } + if ((type = typeof newValue) !== 'boolean') { + if (type === 'string') { + newValue = (newValue == "true"); + } else { + newValue = new Boolean(newValue).valueOf(); + } + } -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; + eventEmitter.emit(RTCEvents.LASTN_CHANGED, oldValue, newValue); + } + else if ("LastNEndpointsChangeEvent" === colibriClass) { + // The new/latest list of last-n endpoint IDs. + var lastNEndpoints = obj.lastNEndpoints; + // The list of endpoint IDs which are entering the list of + // last-n at this time i.e. were not in the old list of last-n + // endpoint IDs. + var endpointsEnteringLastN = obj.endpointsEnteringLastN; + + console.log( + "Data channel new last-n event: ", + lastNEndpoints, endpointsEnteringLastN, obj); + eventEmitter.emit(RTCEvents.LASTN_ENDPOINT_CHANGED, + lastNEndpoints, endpointsEnteringLastN, obj); + } + else { + console.debug("Data channel JSON-formatted message: ", obj); + } + } + }; -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; + dataChannel.onclose = function () { + console.info("The Data Channel closed", dataChannel); + var idx = _dataChannels.indexOf(dataChannel); + if (idx > -1) + _dataChannels = _dataChannels.splice(idx, 1); + }; + _dataChannels.push(dataChannel); + }, + + /** + * Binds "ondatachannel" event listener to given PeerConnection instance. + * @param peerConnection WebRTC peer connection instance. + */ + init: function (peerConnection, emitter) { + if(!config.openSctp) + return; + + peerConnection.ondatachannel = this.onDataChannel; + eventEmitter = emitter; + + // Sample code for opening new data channel from Jitsi Meet to the bridge. + // Although it's not a requirement to open separate channels from both bridge + // and peer as single channel can be used for sending and receiving data. + // So either channel opened by the bridge or the one opened here is enough + // for communication with the bridge. + /*var dataChannelOptions = + { + reliable: true + }; + var dataChannel + = peerConnection.createDataChannel("myChannel", dataChannelOptions); + + // Can be used only when is in open state + dataChannel.onopen = function () + { + dataChannel.send("My channel !!!"); + }; + dataChannel.onmessage = function (event) + { + var msgData = event.data; + console.info("Got My Data Channel Message:", msgData, dataChannel); + };*/ + }, + handleSelectedEndpointEvent: onSelectedEndpointChanged, + handlePinnedEndpointEvent: onPinnedEndpointChanged }; -function isFunction(arg) { - return typeof arg === 'function'; -} +function onSelectedEndpointChanged(userResource) { + console.log('selected endpoint changed: ', userResource); + if (_dataChannels && _dataChannels.length != 0) { + _dataChannels.some(function (dataChannel) { + if (dataChannel.readyState == 'open') { + console.log('sending selected endpoint changed ' + + 'notification to the bridge: ', userResource); + dataChannel.send(JSON.stringify({ + 'colibriClass': 'SelectedEndpointChangedEvent', + 'selectedEndpoint': + (!userResource || userResource === null)? + null : userResource + })); -function isNumber(arg) { - return typeof arg === 'number'; + return true; + } + }); + } } -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} +function onPinnedEndpointChanged(userResource) { + console.log('pinned endpoint changed: ', userResource); + if (_dataChannels && _dataChannels.length != 0) { + _dataChannels.some(function (dataChannel) { + if (dataChannel.readyState == 'open') { + dataChannel.send(JSON.stringify({ + 'colibriClass': 'PinnedEndpointChangedEvent', + 'pinnedEndpoint': + (!userResource || userResource == null)? + null : userResource + })); -function isUndefined(arg) { - return arg === void 0; + return true; + } + }); + } } -},{}],2:[function(require,module,exports){ -// shim for using process in browser +module.exports = DataChannels; -var process = module.exports = {}; -var queue = []; -var draining = false; -function drainQueue() { - if (draining) { - return; - } - draining = true; - var currentQueue; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - var i = -1; - while (++i < len) { - currentQueue[i](); - } - len = queue.length; +},{"../../service/RTC/RTCEvents":99}],5:[function(require,module,exports){ +/* global APP */ +var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js"); +var RTCEvents = require("../../service/RTC/RTCEvents"); + +function LocalStream(stream, type, eventEmitter, videoType, isGUMStream) { + this.stream = stream; + this.eventEmitter = eventEmitter; + this.type = type; + this.videoType = videoType; + this.isGUMStream = true; + if(isGUMStream === false) + this.isGUMStream = isGUMStream; + var self = this; + if(type == "audio") { + this.getTracks = function () { + return self.stream.getAudioTracks(); + }; + } else { + this.getTracks = function () { + return self.stream.getVideoTracks(); + }; } - draining = false; + + this.stream.onended = function() { + self.streamEnded(); + }; } -process.nextTick = function (fun) { - queue.push(fun); - if (!draining) { - setTimeout(drainQueue, 0); - } + +LocalStream.prototype.streamEnded = function () { + this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this); }; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; +LocalStream.prototype.getOriginalStream = function() +{ + return this.stream; +}; -function noop() {} +LocalStream.prototype.isAudioStream = function () { + return this.type === "audio"; +}; -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; +LocalStream.prototype.setMute = function (mute) +{ + var isAudio = this.isAudioStream(); + var eventType = isAudio ? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE; -process.binding = function (name) { - throw new Error('process.binding is not supported'); + if ((window.location.protocol != "https:" && this.isGUMStream) || + (isAudio && this.isGUMStream) || this.videoType === "screen") { + var tracks = this.getTracks(); + + for (var idx = 0; idx < tracks.length; idx++) { + tracks[idx].enabled = !mute; + } + this.eventEmitter.emit(eventType, mute); + } else { + if (mute) { + APP.xmpp.removeStream(this.stream); + this.stream.stop(); + this.eventEmitter.emit(eventType, true); + } else { + var self = this; + APP.RTC.rtcUtils.obtainAudioAndVideoPermissions( + (this.isAudioStream() ? ["audio"] : ["video"]), + function (stream) { + if (isAudio) { + APP.RTC.changeLocalAudio(stream, + function () { + self.eventEmitter.emit(eventType, false); + }); + } else { + APP.RTC.changeLocalVideo(stream, false, + function () { + self.eventEmitter.emit(eventType, false); + }); + } + }); + } + } }; -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); +LocalStream.prototype.isMuted = function () { + var tracks = []; + if (this.isAudioStream()) { + tracks = this.stream.getAudioTracks(); + } else { + if (this.stream.ended) + return true; + tracks = this.stream.getVideoTracks(); + } + for (var idx = 0; idx < tracks.length; idx++) { + if(tracks[idx].enabled) + return false; + } + return true; }; -process.umask = function() { return 0; }; -},{}],3:[function(require,module,exports){ -/* jshint -W117 */ -/* application specific logic */ - -var APP = -{ - init: function () { - this.UI = require("./modules/UI/UI"); - this.API = require("./modules/API/API"); - this.connectionquality = require("./modules/connectionquality/connectionquality"); - this.statistics = require("./modules/statistics/statistics"); - this.RTC = require("./modules/RTC/RTC"); - this.desktopsharing = require("./modules/desktopsharing/desktopsharing"); - this.xmpp = require("./modules/xmpp/xmpp"); - this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut"); - this.translation = require("./modules/translation/translation"); - this.settings = require("./modules/settings/Settings"); - this.DTMF = require("./modules/DTMF/DTMF"); - this.members = require("./modules/members/MemberList"); - } -}; - -function init() { - - APP.desktopsharing.init(); - APP.RTC.start(); - APP.xmpp.start(); - APP.statistics.start(); - APP.connectionquality.init(); - APP.keyboardshortcut.init(); - APP.members.start(); -} - - -$(document).ready(function () { - - var URLPRocessor = require("./modules/URLProcessor/URLProcessor"); - URLPRocessor.setConfigParametersFromUrl(); - APP.init(); - - APP.translation.init(); - - if(APP.API.isEnabled()) - APP.API.init(); - - APP.UI.start(init); - -}); - -$(window).bind('beforeunload', function () { - if(APP.API.isEnabled()) - APP.API.dispose(); -}); - -module.exports = APP; - - -},{"./modules/API/API":4,"./modules/DTMF/DTMF":5,"./modules/RTC/RTC":9,"./modules/UI/UI":13,"./modules/URLProcessor/URLProcessor":44,"./modules/connectionquality/connectionquality":45,"./modules/desktopsharing/desktopsharing":46,"./modules/keyboardshortcut/keyboardshortcut":47,"./modules/members/MemberList":48,"./modules/settings/Settings":49,"./modules/statistics/statistics":53,"./modules/translation/translation":54,"./modules/xmpp/xmpp":68}],4:[function(require,module,exports){ -/** - * Implements API class that communicates with external api class - * and provides interface to access Jitsi Meet features by external - * applications that embed Jitsi Meet - */ - -var XMPPEvents = require("../../service/xmpp/XMPPEvents"); - -/** - * List of the available commands. - * @type {{ - * displayName: inputDisplayNameHandler, - * muteAudio: toggleAudio, - * muteVideo: toggleVideo, - * filmStrip: toggleFilmStrip - * }} - */ -var commands = {}; - -function initCommands() { - commands = - { - displayName: APP.UI.inputDisplayNameHandler, - muteAudio: APP.UI.toggleAudio, - muteVideo: APP.UI.toggleVideo, - toggleFilmStrip: APP.UI.toggleFilmStrip, - toggleChat: APP.UI.toggleChat, - toggleContactList: APP.UI.toggleContactList - }; -} - - -/** - * Maps the supported events and their status - * (true it the event is enabled and false if it is disabled) - * @type {{ - * incomingMessage: boolean, - * outgoingMessage: boolean, - * displayNameChange: boolean, - * participantJoined: boolean, - * participantLeft: boolean - * }} - */ -var events = -{ - incomingMessage: false, - outgoingMessage:false, - displayNameChange: false, - participantJoined: false, - participantLeft: false -}; - -var displayName = {}; - -/** - * Processes commands from external applicaiton. - * @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."); - } - -} - -/** - * Sends message to the external application. - * @param object - */ -function sendMessage(object) { - window.parent.postMessage(JSON.stringify(object), "*"); -} - -/** - * 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) {} - - if(!message.type) - return; - switch (message.type) - { - case "command": - processCommand(message); - break; - case "event": - processEvent(message); - break; - default: - console.error("Unknown type of the message"); - return; - } - -} - -function setupListeners() { - APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, function (from) { - API.triggerEvent("participantJoined", {jid: from}); - }); - APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid, stamp) { - if (from != myjid) - API.triggerEvent("incomingMessage", - {"from": from, "nick": nick, "message": txt, "stamp": stamp}); - }); - APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, function (jid) { - API.triggerEvent("participantLeft", {jid: jid}); - }); - APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) { - name = displayName[jid]; - if(!name || name != newDisplayName) { - API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName}); - displayName[jid] = newDisplayName; - } - }); - APP.xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) { - APP.API.triggerEvent("outgoingMessage", {"message": body}); - }); -} - -var API = { - /** - * Check whether the API should be enabled or not. - * @returns {boolean} - */ - isEnabled: function () { - var hash = location.hash; - if(hash && hash.indexOf("external") > -1 && window.postMessage) - return true; - return false; - }, - /** - * Initializes the APIConnector. Setups message event listeners that will - * receive information from external applications that embed Jitsi Meet. - * It also sends a message to the external application that APIConnector - * is initialized. - */ - init: function () { - initCommands(); - if (window.addEventListener) - { - window.addEventListener('message', - processMessage, false); - } - else - { - window.attachEvent('onmessage', processMessage); - } - sendMessage({type: "system", loaded: true}); - setupListeners(); - }, - /** - * Checks whether the event is enabled ot not. - * @param name the name of the event. - * @returns {*} - */ - isEventEnabled: function (name) { - return events[name]; - }, - - /** - * Sends event object to the external application that has been subscribed - * for that event. - * @param name the name event - * @param object data associated with the event - */ - triggerEvent: function (name, object) { - if(this.isEnabled() && this.isEventEnabled(name)) - sendMessage({ - type: "event", action: "result", event: name, result: object}); - }, - - /** - * Removes the listeners. - */ - dispose: function () { - if(window.removeEventListener) - { - window.removeEventListener("message", - processMessage, false); - } - else - { - window.detachEvent('onmessage', processMessage); - } - - } - - -}; - -module.exports = API; -},{"../../service/xmpp/XMPPEvents":110}],5:[function(require,module,exports){ -/* global APP */ - -/** - * A module for sending DTMF tones. - */ -var DTMFSender; -var initDtmfSender = function() { - // TODO: This needs to reset this if the peerconnection changes - // (e.g. the call is re-made) - if (DTMFSender) - return; - - var localAudio = APP.RTC.localAudio; - if (localAudio && localAudio.getTracks().length > 0) - { - var peerconnection - = APP.xmpp.getConnection().jingle.activecall.peerconnection; - if (peerconnection) { - DTMFSender = - peerconnection.peerconnection - .createDTMFSender(localAudio.getTracks()[0]); - console.log("Initialized DTMFSender"); - } - else { - console.log("Failed to initialize DTMFSender: no PeerConnection."); - } - } - else { - console.log("Failed to initialize DTMFSender: no audio track."); - } -}; - -var DTMF = { - sendTones: function (tones, duration, pause) { - if (!DTMFSender) - initDtmfSender(); - - if (DTMFSender){ - DTMFSender.insertDTMF(tones, - (duration || 200), - (pause || 200)); - } - } -}; - -module.exports = DTMF; - - -},{}],6:[function(require,module,exports){ -/* global Strophe, focusedVideoSrc*/ - -// cache datachannels to avoid garbage collection -// https://code.google.com/p/chromium/issues/detail?id=405545 -var RTCEvents = require("../../service/RTC/RTCEvents"); - -var _dataChannels = []; -var eventEmitter = null; - - - - -var DataChannels = -{ - - /** - * Callback triggered by PeerConnection when new data channel is opened - * on the bridge. - * @param event the event info object. - */ - - onDataChannel: function (event) - { - var dataChannel = event.channel; - - dataChannel.onopen = function () { - console.info("Data channel opened by the Videobridge!", dataChannel); - - // Code sample for sending string and/or binary data - // Sends String message to the bridge - //dataChannel.send("Hello bridge!"); - // Sends 12 bytes binary message to the bridge - //dataChannel.send(new ArrayBuffer(12)); - - eventEmitter.emit(RTCEvents.DATA_CHANNEL_OPEN); - }; - - dataChannel.onerror = function (error) { - console.error("Data Channel Error:", error, dataChannel); - }; - - dataChannel.onmessage = function (event) { - var data = event.data; - // JSON - var obj; - - try { - obj = JSON.parse(data); - } - catch (e) { - console.error( - "Failed to parse data channel message as JSON: ", - data, - dataChannel); - } - if (('undefined' !== typeof(obj)) && (null !== obj)) { - var colibriClass = obj.colibriClass; - - if ("DominantSpeakerEndpointChangeEvent" === colibriClass) { - // Endpoint ID from the Videobridge. - var dominantSpeakerEndpoint = obj.dominantSpeakerEndpoint; - - console.info( - "Data channel new dominant speaker event: ", - dominantSpeakerEndpoint); - eventEmitter.emit(RTCEvents.DOMINANTSPEAKER_CHANGED, dominantSpeakerEndpoint); - } - else if ("InLastNChangeEvent" === colibriClass) - { - var oldValue = obj.oldValue; - var newValue = obj.newValue; - // Make sure that oldValue and newValue are of type boolean. - var type; - - if ((type = typeof oldValue) !== 'boolean') { - if (type === 'string') { - oldValue = (oldValue == "true"); - } else { - oldValue = new Boolean(oldValue).valueOf(); - } - } - if ((type = typeof newValue) !== 'boolean') { - if (type === 'string') { - newValue = (newValue == "true"); - } else { - newValue = new Boolean(newValue).valueOf(); - } - } - - eventEmitter.emit(RTCEvents.LASTN_CHANGED, oldValue, newValue); - } - else if ("LastNEndpointsChangeEvent" === colibriClass) - { - // The new/latest list of last-n endpoint IDs. - var lastNEndpoints = obj.lastNEndpoints; - // The list of endpoint IDs which are entering the list of - // last-n at this time i.e. were not in the old list of last-n - // endpoint IDs. - var endpointsEnteringLastN = obj.endpointsEnteringLastN; - var stream = obj.stream; - - console.log( - "Data channel new last-n event: ", - lastNEndpoints, endpointsEnteringLastN, obj); - eventEmitter.emit(RTCEvents.LASTN_ENDPOINT_CHANGED, - lastNEndpoints, endpointsEnteringLastN, obj); - } - else - { - console.debug("Data channel JSON-formatted message: ", obj); - } - } - }; - - dataChannel.onclose = function () - { - console.info("The Data Channel closed", dataChannel); - var idx = _dataChannels.indexOf(dataChannel); - if (idx > -1) - _dataChannels = _dataChannels.splice(idx, 1); - }; - _dataChannels.push(dataChannel); - }, - - /** - * Binds "ondatachannel" event listener to given PeerConnection instance. - * @param peerConnection WebRTC peer connection instance. - */ - init: function (peerConnection, emitter) { - if(!config.openSctp) - return; - - peerConnection.ondatachannel = this.onDataChannel; - eventEmitter = emitter; - - // Sample code for opening new data channel from Jitsi Meet to the bridge. - // Although it's not a requirement to open separate channels from both bridge - // and peer as single channel can be used for sending and receiving data. - // So either channel opened by the bridge or the one opened here is enough - // for communication with the bridge. - /*var dataChannelOptions = - { - reliable: true - }; - var dataChannel - = peerConnection.createDataChannel("myChannel", dataChannelOptions); - - // Can be used only when is in open state - dataChannel.onopen = function () - { - dataChannel.send("My channel !!!"); - }; - dataChannel.onmessage = function (event) - { - var msgData = event.data; - console.info("Got My Data Channel Message:", msgData, dataChannel); - };*/ - }, - handleSelectedEndpointEvent: onSelectedEndpointChanged, - handlePinnedEndpointEvent: onPinnedEndpointChanged - -}; - -function onSelectedEndpointChanged(userResource) -{ - console.log('selected endpoint changed: ', userResource); - if (_dataChannels && _dataChannels.length != 0) - { - _dataChannels.some(function (dataChannel) { - if (dataChannel.readyState == 'open') - { - console.log('sending selected endpoint changed ' - + 'notification to the bridge: ', userResource); - dataChannel.send(JSON.stringify({ - 'colibriClass': 'SelectedEndpointChangedEvent', - 'selectedEndpoint': - (!userResource || userResource === null)? - null : userResource - })); - - return true; - } - }); - } -} - -function onPinnedEndpointChanged(userResource) -{ - console.log('pinned endpoint changed: ', userResource); - if (_dataChannels && _dataChannels.length != 0) - { - _dataChannels.some(function (dataChannel) { - if (dataChannel.readyState == 'open') - { - dataChannel.send(JSON.stringify({ - 'colibriClass': 'PinnedEndpointChangedEvent', - 'pinnedEndpoint': - (!userResource || userResource == null)? - null : userResource - })); - - return true; - } - }); - } -} - -module.exports = DataChannels; - - -},{"../../service/RTC/RTCEvents":101}],7:[function(require,module,exports){ -var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js"); -var RTCEvents = require("../../service/RTC/RTCEvents"); - - -function LocalStream(stream, type, eventEmitter, videoType, isGUMStream) -{ - this.stream = stream; - this.eventEmitter = eventEmitter; - this.type = type; - this.videoType = videoType; - this.isGUMStream = true; - if(isGUMStream === false) - this.isGUMStream = isGUMStream; - var self = this; - if(type == "audio") - { - this.getTracks = function () { - return self.stream.getAudioTracks(); - }; - } - else - { - this.getTracks = function () { - return self.stream.getVideoTracks(); - }; - } - - this.stream.onended = function() - { - self.streamEnded(); - }; -} - -LocalStream.prototype.streamEnded = function () { - this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this); -} - -LocalStream.prototype.getOriginalStream = function() -{ - return this.stream; -} - -LocalStream.prototype.isAudioStream = function () { - return this.type === "audio"; -}; - -LocalStream.prototype.setMute = function (mute) -{ - var isAudio = this.isAudioStream(); - var eventType = isAudio ? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE; - - if ((window.location.protocol != "https:" && this.isGUMStream) || - (isAudio && this.isGUMStream) || this.videoType === "screen") - { - var tracks = this.getTracks(); - - for (var idx = 0; idx < tracks.length; idx++) { - tracks[idx].enabled = !mute; - } - this.eventEmitter.emit(eventType, mute); - } - else - { - if (mute) { - APP.xmpp.removeStream(this.stream); - this.stream.stop(); - this.eventEmitter.emit(eventType, true); - } - else - { - var self = this; - APP.RTC.rtcUtils.obtainAudioAndVideoPermissions( - (this.isAudioStream() ? ["audio"] : ["video"]), - function (stream) { - if (isAudio) - { - APP.RTC.changeLocalAudio(stream, - function () { - self.eventEmitter.emit(eventType, false); - }); - } - else - { - APP.RTC.changeLocalVideo(stream, false, - function () { - self.eventEmitter.emit(eventType, false); - }); - } - }); - } - } -}; - -LocalStream.prototype.isMuted = function () { - var tracks = []; - if(this.type == "audio") - { - tracks = this.stream.getAudioTracks(); - } - else - { - if(this.stream.ended) - return true; - tracks = this.stream.getVideoTracks(); - } - for (var idx = 0; idx < tracks.length; idx++) { - if(tracks[idx].enabled) - return false; - } - return true; -} - -LocalStream.prototype.getId = function () { - return this.stream.getTracks()[0].id; -} - -module.exports = LocalStream; - -},{"../../service/RTC/RTCEvents":101,"../../service/RTC/StreamEventTypes.js":103}],8:[function(require,module,exports){ -////These lines should be uncommented when require works in app.js -var MediaStreamType = require("../../service/RTC/MediaStreamTypes"); -var StreamEventType = require("../../service/RTC/StreamEventTypes"); - -/** - * Creates a MediaStream object for the given data, session id and ssrc. - * It is a wrapper class for the MediaStream. - * - * @param data the data object from which we obtain the stream, - * the peerjid, etc. - * @param sid the session id - * @param ssrc the ssrc corresponding to this MediaStream - * - * @constructor - */ -function MediaStream(data, sid, ssrc, browser, eventEmitter) { - - // XXX(gp) to minimize headaches in the future, we should build our - // abstractions around tracks and not streams. ORTC is track based API. - // Mozilla expects m-lines to represent media tracks. - // - // Practically, what I'm saying is that we should have a MediaTrack class - // and not a MediaStream class. - // - // Also, we should be able to associate multiple SSRCs with a MediaTrack as - // a track might have an associated RTX and FEC sources. - - this.sid = sid; - this.stream = data.stream; - this.peerjid = data.peerjid; - this.videoType = data.videoType; - this.ssrc = ssrc; - this.type = (this.stream.getVideoTracks().length > 0)? - MediaStreamType.VIDEO_TYPE : MediaStreamType.AUDIO_TYPE; - this.muted = false; - this.eventEmitter = eventEmitter; -} - - -MediaStream.prototype.getOriginalStream = function() -{ - return this.stream; -}; - -MediaStream.prototype.setMute = function (value) -{ - this.stream.muted = value; - this.muted = value; -}; - -module.exports = MediaStream; - -},{"../../service/RTC/MediaStreamTypes":100,"../../service/RTC/StreamEventTypes":103}],9:[function(require,module,exports){ -var EventEmitter = require("events"); -var RTCBrowserType = require("./RTCBrowserType"); -var RTCUtils = require("./RTCUtils.js"); -var LocalStream = require("./LocalStream.js"); -var DataChannels = require("./DataChannels"); -var MediaStream = require("./MediaStream.js"); -var DesktopSharingEventTypes - = require("../../service/desktopsharing/DesktopSharingEventTypes"); -var MediaStreamType = require("../../service/RTC/MediaStreamTypes"); -var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js"); -var RTCEvents = require("../../service/RTC/RTCEvents.js"); -var XMPPEvents = require("../../service/xmpp/XMPPEvents"); -var UIEvents = require("../../service/UI/UIEvents"); - -var eventEmitter = new EventEmitter(); - - -function getMediaStreamUsage() -{ - var result = { - audio: true, - video: true - }; - - /** There are some issues with the desktop sharing - * when this property is enabled. - * WARNING: We must change the implementation to start video/audio if we - * receive from the focus that the peer is not muted. - - var isSecureConnection = window.location.protocol == "https:"; - - if(config.disableEarlyMediaPermissionRequests || !isSecureConnection) - { - result = { - audio: false, - video: false - }; - - } - **/ - - return result; -} - -var RTC = { - rtcUtils: null, - devices: { - audio: true, - video: true - }, - localStreams: [], - remoteStreams: {}, - localAudio: null, - localVideo: null, - addStreamListener: function (listener, eventType) { - eventEmitter.on(eventType, listener); - }, - addListener: function (type, listener) { - eventEmitter.on(type, listener); - }, - removeStreamListener: function (listener, eventType) { - if(!(eventType instanceof StreamEventTypes)) - throw "Illegal argument"; - - eventEmitter.removeListener(eventType, listener); - }, - createLocalStream: function (stream, type, change, videoType, isMuted, isGUMStream) { - - var localStream = new LocalStream(stream, type, eventEmitter, videoType, isGUMStream); - //in firefox we have only one stream object - if(this.localStreams.length == 0 || - this.localStreams[0].getOriginalStream() != stream) - this.localStreams.push(localStream); - if(isMuted === true) - localStream.setMute(true); - - if(type == "audio") { - this.localAudio = localStream; - } else { - this.localVideo = localStream; - } - var eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CREATED; - if(change) - eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED; - - eventEmitter.emit(eventType, localStream, isMuted); - return localStream; - }, - removeLocalStream: function (stream) { - for(var i = 0; i < this.localStreams.length; i++) - { - if(this.localStreams[i].getOriginalStream() === stream) { - delete this.localStreams[i]; - return; - } - } - }, - createRemoteStream: function (data, sid, thessrc) { - var remoteStream = new MediaStream(data, sid, thessrc, - RTCBrowserType.getBrowserType(), eventEmitter); - var jid = data.peerjid || APP.xmpp.myJid(); - if(!this.remoteStreams[jid]) { - this.remoteStreams[jid] = {}; - } - this.remoteStreams[jid][remoteStream.type]= remoteStream; - eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream); - return remoteStream; - }, - getPCConstraints: function () { - return this.rtcUtils.pc_constraints; - }, - getUserMediaWithConstraints:function(um, success_callback, - failure_callback, resolution, - bandwidth, fps, desktopStream) - { - return this.rtcUtils.getUserMediaWithConstraints(um, success_callback, - failure_callback, resolution, bandwidth, fps, desktopStream); - }, - attachMediaStream: function (elSelector, stream) { - this.rtcUtils.attachMediaStream(elSelector, stream); - }, - getStreamID: function (stream) { - return this.rtcUtils.getStreamID(stream); - }, - getVideoSrc: function (element) { - return this.rtcUtils.getVideoSrc(element); - }, - setVideoSrc: function (element, src) { - this.rtcUtils.setVideoSrc(element, src); - }, - getVideoElementName: function () { - return RTCBrowserType.isTemasysPluginUsed() ? 'object' : 'video'; - }, - dispose: function() { - if (this.rtcUtils) { - this.rtcUtils = null; - } - }, - stop: function () { - this.dispose(); - }, - start: function () { - var self = this; - APP.desktopsharing.addListener( - function (stream, isUsingScreenStream, callback) { - self.changeLocalVideo(stream, isUsingScreenStream, callback); - }, DesktopSharingEventTypes.NEW_STREAM_CREATED); - APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function(event) { - DataChannels.init(event.peerconnection, eventEmitter); - }); - APP.UI.addListener(UIEvents.SELECTED_ENDPOINT, - DataChannels.handleSelectedEndpointEvent); - APP.UI.addListener(UIEvents.PINNED_ENDPOINT, - DataChannels.handlePinnedEndpointEvent); - - // In case of IE we continue from 'onReady' callback - // passed to RTCUtils constructor. It will be invoked by Temasys plugin - // once it is initialized. - var onReady = function () { - eventEmitter.emit(RTCEvents.RTC_READY, true); - self.rtcUtils.obtainAudioAndVideoPermissions( - null, null, getMediaStreamUsage()); - }; - - this.rtcUtils = new RTCUtils(this, onReady); - - // Call onReady() if Temasys plugin is not used - if (!RTCBrowserType.isTemasysPluginUsed()) { - onReady(); - } - }, - muteRemoteVideoStream: function (jid, value) { - var stream; - - if(this.remoteStreams[jid] && - this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) - { - stream = this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]; - } - - if(!stream) - return true; - - if (value != stream.muted) { - stream.setMute(value); - return true; - } - return false; - }, - switchVideoStreams: function (new_stream) { - this.localVideo.stream = new_stream; - - this.localStreams = []; - - //in firefox we have only one stream object - if (this.localAudio.getOriginalStream() != new_stream) - this.localStreams.push(this.localAudio); - this.localStreams.push(this.localVideo); - }, - changeLocalVideo: function (stream, isUsingScreenStream, callback) { - var oldStream = this.localVideo.getOriginalStream(); - var type = (isUsingScreenStream? "screen" : "video"); - var localCallback = callback; - if(this.localVideo.isMuted() && this.localVideo.videoType !== type) - { - localCallback = function() { - APP.xmpp.setVideoMute(false, function(mute) { - eventEmitter.emit(RTCEvents.VIDEO_MUTE, mute); - }); - - callback(); - }; - } - // FIXME: Workaround for FF/IE/Safari - if (stream && stream.videoStream) { - stream = stream.videoStream; - } - var videoStream = this.rtcUtils.createStream(stream, true); - this.localVideo = this.createLocalStream(videoStream, "video", true, type); - // Stop the stream to trigger onended event for old stream - oldStream.stop(); - - this.switchVideoStreams(videoStream, oldStream); - - APP.xmpp.switchStreams(videoStream, oldStream,localCallback); - }, - changeLocalAudio: function (stream, callback) { - var oldStream = this.localAudio.getOriginalStream(); - var newStream = this.rtcUtils.createStream(stream); - this.localAudio = this.createLocalStream(newStream, "audio", true); - // Stop the stream to trigger onended event for old stream - oldStream.stop(); - APP.xmpp.switchStreams(newStream, oldStream, callback, true); - }, - isVideoMuted: function (jid) { - if (jid === APP.xmpp.myJid()) { - var localVideo = APP.RTC.localVideo; - return (!localVideo || localVideo.isMuted()); - } - else - { - if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) { - return null; - } - return APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted; - } - }, - /** - * Checks if video identified by given src is desktop stream. - * @param videoSrc eg. - * blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395 - * @returns {boolean} - */ - isVideoSrcDesktop: function (jid) { - if(!jid) - return false; - var isDesktop = false; - var stream = null; - if (APP.xmpp.myJid() === jid) { - // local video - stream = this.localVideo; - } else { - var peerStreams = this.remoteStreams[jid]; - if(!peerStreams) - return false; - stream = peerStreams[MediaStreamType.VIDEO_TYPE]; - } - - if(stream) - isDesktop = (stream.videoType === "screen"); - - return isDesktop; - }, - setVideoMute: function (mute, callback, options) { - if (!this.localVideo) - return; - - if (mute == APP.RTC.localVideo.isMuted()) - { - APP.xmpp.sendVideoInfoPresence(mute); - if (callback) - callback(mute); - } - else - { - APP.RTC.localVideo.setMute(mute); - APP.xmpp.setVideoMute( - mute, - callback, - options); - } - }, - setDeviceAvailability: function (devices) { - if(!devices) - return; - if(devices.audio === true || devices.audio === false) - this.devices.audio = devices.audio; - if(devices.video === true || devices.video === false) - this.devices.video = devices.video; - eventEmitter.emit(RTCEvents.AVAILABLE_DEVICES_CHANGED, this.devices); - } -}; - -module.exports = RTC; - -},{"../../service/RTC/MediaStreamTypes":100,"../../service/RTC/RTCEvents.js":101,"../../service/RTC/StreamEventTypes.js":103,"../../service/UI/UIEvents":104,"../../service/desktopsharing/DesktopSharingEventTypes":107,"../../service/xmpp/XMPPEvents":110,"./DataChannels":6,"./LocalStream.js":7,"./MediaStream.js":8,"./RTCBrowserType":10,"./RTCUtils.js":11,"events":1}],10:[function(require,module,exports){ - -var currentBrowser; - -var browserVersion; - -var RTCBrowserType = { - - RTC_BROWSER_CHROME: "rtc_browser.chrome", - - RTC_BROWSER_OPERA: "rtc_browser.opera", - - RTC_BROWSER_FIREFOX: "rtc_browser.firefox", - - RTC_BROWSER_IEXPLORER: "rtc_browser.iexplorer", - - RTC_BROWSER_SAFARI: "rtc_browser.safari", - - getBrowserType: function () { - return currentBrowser; - }, - - isChrome: function () { - return currentBrowser === RTCBrowserType.RTC_BROWSER_CHROME; - }, - - isOpera: function () { - return currentBrowser === RTCBrowserType.RTC_BROWSER_OPERA; - }, - isFirefox: function () { - return currentBrowser === RTCBrowserType.RTC_BROWSER_FIREFOX; - }, - - isIExplorer: function () { - return currentBrowser === RTCBrowserType.RTC_BROWSER_IEXPLORER; - }, - - isSafari: function () { - return currentBrowser === RTCBrowserType.RTC_BROWSER_SAFARI; - }, - isTemasysPluginUsed: function () { - return RTCBrowserType.isIExplorer() || RTCBrowserType.isSafari(); - }, - getFirefoxVersion: function () { - return RTCBrowserType.isFirefox() ? browserVersion : null; - }, - - getChromeVersion: function () { - return RTCBrowserType.isChrome() ? browserVersion : null; - }, - - usesPlanB: function() { - return RTCBrowserType.isChrome() || RTCBrowserType.isOpera() - || RTCBrowserType.isTemasysPluginUsed(); - }, - - usesUnifiedPlan: function() { - return RTCBrowserType.isFirefox(); - } - - // Add version getters for other browsers when needed -}; - -// detectOpera() must be called before detectChrome() !!! -// otherwise Opera wil be detected as Chrome -function detectChrome() { - if (navigator.webkitGetUserMedia) { - currentBrowser = RTCBrowserType.RTC_BROWSER_CHROME; - var userAgent = navigator.userAgent.toLowerCase(); - // We can assume that user agent is chrome, because it's - // enforced when 'ext' streaming method is set - var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10); - console.log("This appears to be Chrome, ver: " + ver); - return ver; - } - return null; -} - -function detectOpera() { - var userAgent = navigator.userAgent; - if (userAgent.match(/Opera|OPR/)) { - currentBrowser = RTCBrowserType.RTC_BROWSER_OPERA; - var version = userAgent.match(/(Opera|OPR) ?\/?(\d+)\.?/)[2]; - console.info("This appears to be Opera, ver: " + version); - return version; - } - return null; -} - -function detectFirefox() { - if (navigator.mozGetUserMedia) { - currentBrowser = RTCBrowserType.RTC_BROWSER_FIREFOX; - var version = parseInt( - navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); - console.log('This appears to be Firefox, ver: ' + version); - return version; - } - return null; -} - -function detectSafari() { - if ((/^((?!chrome).)*safari/i.test(navigator.userAgent))) { - currentBrowser = RTCBrowserType.RTC_BROWSER_SAFARI; - console.info("This appears to be Safari"); - // FIXME detect Safari version when needed - return 1; - } - return null; -} - -function detectIE() { - var version; - var ua = window.navigator.userAgent; - - var msie = ua.indexOf('MSIE '); - if (msie > 0) { - // IE 10 or older => return version number - version = parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); - } - - var trident = ua.indexOf('Trident/'); - if (!version && trident > 0) { - // IE 11 => return version number - var rv = ua.indexOf('rv:'); - version = parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); - } - - var edge = ua.indexOf('Edge/'); - if (!version && edge > 0) { - // IE 12 => return version number - version = parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); - } - - if (version) { - currentBrowser = RTCBrowserType.RTC_BROWSER_IEXPLORER; - console.info("This appears to be IExplorer, ver: " + version); - } - return version; -} - -function detectBrowser() { - var version; - var detectors = [ - detectOpera, - detectChrome, - detectFirefox, - detectIE, - detectSafari - ]; - // Try all browser detectors - for (var i = 0; i < detectors.length; i++) { - version = detectors[i](); - if (version) - return version; - } - console.error("Failed to detect browser type"); - return undefined; -} - -browserVersion = detectBrowser(); - -module.exports = RTCBrowserType; -},{}],11:[function(require,module,exports){ -var RTCBrowserType = require("./RTCBrowserType"); -var Resolutions = require("../../service/RTC/Resolutions"); -var AdapterJS = require("./adapter.screenshare"); -var SDPUtil = require("../xmpp/SDPUtil"); - -var currentResolution = null; - -function getPreviousResolution(resolution) { - if(!Resolutions[resolution]) - return null; - var order = Resolutions[resolution].order; - var res = null; - var resName = null; - for(var i in Resolutions) - { - var tmp = Resolutions[i]; - if(res == null || (res.order < tmp.order && tmp.order < order)) - { - resName = i; - res = tmp; - } - } - return resName; -} - -function setResolutionConstraints(constraints, resolution, isAndroid) -{ - if (resolution && !constraints.video || isAndroid) { - constraints.video = { mandatory: {}, optional: [] };// same behaviour as true - } - - if(Resolutions[resolution]) - { - constraints.video.mandatory.minWidth = Resolutions[resolution].width; - constraints.video.mandatory.minHeight = Resolutions[resolution].height; - } - else - { - if (isAndroid) { - constraints.video.mandatory.minWidth = 320; - constraints.video.mandatory.minHeight = 240; - constraints.video.mandatory.maxFrameRate = 15; - } - } - - if (constraints.video.mandatory.minWidth) - constraints.video.mandatory.maxWidth = constraints.video.mandatory.minWidth; - if (constraints.video.mandatory.minHeight) - constraints.video.mandatory.maxHeight = constraints.video.mandatory.minHeight; -} - -function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid) -{ - var constraints = {audio: false, video: false}; - - if (um.indexOf('video') >= 0) { - constraints.video = { mandatory: {}, optional: [] };// same behaviour as true - } - if (um.indexOf('audio') >= 0) { - constraints.audio = { mandatory: {}, optional: []};// same behaviour as true - } - if (um.indexOf('screen') >= 0) { - if (RTCBrowserType.isChrome()) { - constraints.video = { - mandatory: { - chromeMediaSource: "screen", - googLeakyBucket: true, - maxWidth: window.screen.width, - maxHeight: window.screen.height, - maxFrameRate: 3 - }, - optional: [] - }; - } else if (RTCBrowserType.isTemasysPluginUsed()) { - constraints.video = { - optional: [ - { - sourceId: AdapterJS.WebRTCPlugin.plugin.screensharingKey - } - ] - }; - } else { - console.error( - "'screen' WebRTC media source is supported only in Chrome" + - " and with Temasys plugin"); - } - } - if (um.indexOf('desktop') >= 0) { - constraints.video = { - mandatory: { - chromeMediaSource: "desktop", - chromeMediaSourceId: desktopStream, - googLeakyBucket: true, - maxWidth: window.screen.width, - maxHeight: window.screen.height, - maxFrameRate: 3 - }, - optional: [] - }; - } - - if (constraints.audio) { - // if it is good enough for hangouts... - constraints.audio.optional.push( - {googEchoCancellation: true}, - {googAutoGainControl: true}, - {googNoiseSupression: true}, - {googHighpassFilter: true}, - {googNoisesuppression2: true}, - {googEchoCancellation2: true}, - {googAutoGainControl2: true} - ); - } - if (constraints.video) { - constraints.video.optional.push( - {googNoiseReduction: false} // chrome 37 workaround for issue 3807, reenable in M38 - ); - if (um.indexOf('video') >= 0) { - constraints.video.optional.push( - {googLeakyBucket: true} - ); - } - } - - if (um.indexOf('video') >= 0) { - setResolutionConstraints(constraints, resolution, isAndroid); - } - - if (bandwidth) { // doesn't work currently, see webrtc issue 1846 - if (!constraints.video) constraints.video = {mandatory: {}, optional: []};//same behaviour as true - constraints.video.optional.push({bandwidth: bandwidth}); - } - if (fps) { // for some cameras it might be necessary to request 30fps - // so they choose 30fps mjpg over 10fps yuy2 - if (!constraints.video) constraints.video = {mandatory: {}, optional: []};// same behaviour as true; - constraints.video.mandatory.minFrameRate = fps; - } - - return constraints; -} - - -function RTCUtils(RTCService, onTemasysPluginReady) -{ - var self = this; - this.service = RTCService; - if (RTCBrowserType.isFirefox()) { - var FFversion = RTCBrowserType.getFirefoxVersion(); - if (FFversion >= 40 && config.useBundle && config.useRtcpMux) { - this.peerconnection = mozRTCPeerConnection; - this.getUserMedia = navigator.mozGetUserMedia.bind(navigator); - this.pc_constraints = {}; - this.attachMediaStream = function (element, stream) { - // srcObject is being standardized and FF will eventually - // support that unprefixed. FF also supports the - // "element.src = URL.createObjectURL(...)" combo, but that - // will be deprecated in favour of srcObject. - // - // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg - // https://github.com/webrtc/samples/issues/302 - if(!element[0]) - return; - element[0].mozSrcObject = stream; - element[0].play(); - }; - this.getStreamID = function (stream) { - var id = stream.id; - if (!id) { - var tracks = stream.getVideoTracks(); - if (!tracks || tracks.length === 0) - { - tracks = stream.getAudioTracks(); - } - id = tracks[0].id; - } - return SDPUtil.filter_special_chars(id); - }; - this.getVideoSrc = function (element) { - if(!element) - return null; - return element.mozSrcObject; - }; - this.setVideoSrc = function (element, src) { - if(element) - element.mozSrcObject = src; - }; - RTCSessionDescription = mozRTCSessionDescription; - RTCIceCandidate = mozRTCIceCandidate; - } else { - console.error( - "Firefox requirements not met, ver: " + FFversion + - ", bundle: " + config.useBundle + - ", rtcp-mux: " + config.useRtcpMux); - window.location.href = 'unsupported_browser.html'; - return; - } - - } else if (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) { - this.peerconnection = webkitRTCPeerConnection; - this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - this.attachMediaStream = function (element, stream) { - element.attr('src', webkitURL.createObjectURL(stream)); - }; - this.getStreamID = function (stream) { - // streams from FF endpoints have the characters '{' and '}' - // that make jQuery choke. - return SDPUtil.filter_special_chars(stream.id); - }; - this.getVideoSrc = function (element) { - if(!element) - return null; - return element.getAttribute("src"); - }; - this.setVideoSrc = function (element, src) { - if(element) - element.setAttribute("src", src); - }; - // DTLS should now be enabled by default but.. - this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]}; - if (navigator.userAgent.indexOf('Android') != -1) { - this.pc_constraints = {}; // disable DTLS on Android - } - if (!webkitMediaStream.prototype.getVideoTracks) { - webkitMediaStream.prototype.getVideoTracks = function () { - return this.videoTracks; - }; - } - if (!webkitMediaStream.prototype.getAudioTracks) { - webkitMediaStream.prototype.getAudioTracks = function () { - return this.audioTracks; - }; - } - } - // Detect IE/Safari - else if (RTCBrowserType.isTemasysPluginUsed()) { - - //AdapterJS.WebRTCPlugin.setLogLevel( - // AdapterJS.WebRTCPlugin.PLUGIN_LOG_LEVELS.VERBOSE); - - AdapterJS.webRTCReady(function (isPlugin) { - - self.peerconnection = RTCPeerConnection; - self.getUserMedia = getUserMedia; - self.attachMediaStream = function (elSel, stream) { - - if (stream.id === "dummyAudio" || stream.id === "dummyVideo") { - return; - } - - attachMediaStream(elSel[0], stream); - }; - self.getStreamID = function (stream) { - var id = SDPUtil.filter_special_chars(stream.label); - return id; - }; - self.getVideoSrc = function (element) { - if (!element) { - console.warn("Attempt to get video SRC of null element"); - return null; - } - var src = null; - var children = element.children; - for (var i = 0; i !== children.length; ++i) { - if (children[i].name === 'streamId') { - return children[i].value; - } - } - //console.info(element.id + " SRC: " + src); - return null; - }; - self.setVideoSrc = function (element, src) { - //console.info("Set video src: ", element, src); - if (!src) { - console.warn("Not attaching video stream, 'src' is null"); - return; - } - AdapterJS.WebRTCPlugin.WaitForPluginReady(); - var stream = AdapterJS.WebRTCPlugin.plugin - .getStreamWithId(AdapterJS.WebRTCPlugin.pageId, src); - attachMediaStream(element, stream); - }; - - onTemasysPluginReady(isPlugin); - }); - } else { - try { - console.log('Browser does not appear to be WebRTC-capable'); - } catch (e) { } - window.location.href = 'unsupported_browser.html'; - } -} - - -RTCUtils.prototype.getUserMediaWithConstraints = function( - um, success_callback, failure_callback, resolution,bandwidth, fps, - desktopStream) -{ - currentResolution = resolution; - // Check if we are running on Android device - var isAndroid = navigator.userAgent.indexOf('Android') != -1; - - var constraints = getConstraints( - um, resolution, bandwidth, fps, desktopStream, isAndroid); - - console.info("Get media constraints", constraints); - - var self = this; - - try { - this.getUserMedia(constraints, - function (stream) { - console.log('onUserMediaSuccess'); - self.setAvailableDevices(um, true); - success_callback(stream); - }, - function (error) { - self.setAvailableDevices(um, false); - console.warn('Failed to get access to local media. Error ', - error, constraints); - if (failure_callback) { - failure_callback(error); - } - }); - } catch (e) { - console.error('GUM failed: ', e); - if(failure_callback) { - failure_callback(e); - } - } -}; - -RTCUtils.prototype.setAvailableDevices = function (um, available) { - var devices = {}; - if(um.indexOf("video") != -1) - { - devices.video = available; - } - if(um.indexOf("audio") != -1) - { - devices.audio = available; - } - this.service.setDeviceAvailability(devices); -} - -/** - * We ask for audio and video combined stream in order to get permissions and - * not to ask twice. - */ -RTCUtils.prototype.obtainAudioAndVideoPermissions = - function(devices, callback, usageOptions) -{ - var self = this; - // Get AV - - var successCallback = function (stream) { - if(callback) - callback(stream, usageOptions); - else - self.successCallback(stream, usageOptions); - }; - - if(!devices) - devices = ['audio', 'video']; - - var newDevices = []; - - - if(usageOptions) - for(var i = 0; i < devices.length; i++) - { - var device = devices[i]; - if(usageOptions[device] === true) - newDevices.push(device); - } - else - newDevices = devices; - - if(newDevices.length === 0) - { - successCallback(); - return; - } - - if (RTCBrowserType.isFirefox() || RTCBrowserType.isTemasysPluginUsed()) { - - // With FF/IE we can't split the stream into audio and video because FF - // doesn't support media stream constructors. So, we need to get the - // audio stream separately from the video stream using two distinct GUM - // calls. Not very user friendly :-( but we don't have many other - // options neither. - // - // Note that we pack those 2 streams in a single object and pass it to - // the successCallback method. - var obtainVideo = function (audioStream) { - self.getUserMediaWithConstraints( - ['video'], - function (videoStream) { - return successCallback({ - audioStream: audioStream, - videoStream: videoStream - }); - }, - function (error) { - console.error( - 'failed to obtain video stream - stop', error); - self.errorCallback(error); - }, - config.resolution || '360'); - }; - var obtainAudio = function () { - self.getUserMediaWithConstraints( - ['audio'], - function (audioStream) { - if (newDevices.indexOf('video') !== -1) - obtainVideo(audioStream); - }, - function (error) { - console.error( - 'failed to obtain audio stream - stop', error); - self.errorCallback(error); - } - ); - }; - if (newDevices.indexOf('audio') !== -1) { - obtainAudio(); - } else { - obtainVideo(null); - } - } else { - this.getUserMediaWithConstraints( - newDevices, - function (stream) { - successCallback(stream); - }, - function (error) { - self.errorCallback(error); - }, - config.resolution || '360'); - } - -}; - -RTCUtils.prototype.successCallback = function (stream, usageOptions) { - // If this is FF or IE, the stream parameter is *not* a MediaStream object, - // it's an object with two properties: audioStream, videoStream. - if (stream && stream.getAudioTracks && stream.getVideoTracks) - console.log('got', stream, stream.getAudioTracks().length, - stream.getVideoTracks().length); - this.handleLocalStream(stream, usageOptions); -}; - -RTCUtils.prototype.errorCallback = function (error) { - var self = this; - console.error('failed to obtain audio/video stream - trying audio only', error); - var resolution = getPreviousResolution(currentResolution); - if(typeof error == "object" && error.constraintName && error.name - && (error.name == "ConstraintNotSatisfiedError" || - error.name == "OverconstrainedError") && - (error.constraintName == "minWidth" || error.constraintName == "maxWidth" || - error.constraintName == "minHeight" || error.constraintName == "maxHeight") - && resolution != null) - { - self.getUserMediaWithConstraints(['audio', 'video'], - function (stream) { - return self.successCallback(stream); - }, function (error) { - return self.errorCallback(error); - }, resolution); - } - else - { - self.getUserMediaWithConstraints( - ['audio'], - function (stream) { - return self.successCallback(stream); - }, - function (error) { - console.error('failed to obtain audio/video stream - stop', - error); - return self.successCallback(null); - } - ); - } - -} - -RTCUtils.prototype.handleLocalStream = function(stream, usageOptions) -{ - // If this is FF, the stream parameter is *not* a MediaStream object, it's - // an object with two properties: audioStream, videoStream. - var audioStream, videoStream; - if(window.webkitMediaStream) - { - audioStream = new webkitMediaStream(); - videoStream = new webkitMediaStream(); - if(stream) { - var audioTracks = stream.getAudioTracks(); - - for (var i = 0; i < audioTracks.length; i++) { - audioStream.addTrack(audioTracks[i]); - } - - var videoTracks = stream.getVideoTracks(); - - for (i = 0; i < videoTracks.length; i++) { - videoStream.addTrack(videoTracks[i]); - } - } - } - else if (RTCBrowserType.isFirefox() || RTCBrowserType.isTemasysPluginUsed()) - { // Firefox and Temasys plugin - if (stream && stream.audioStream) - audioStream = stream.audioStream; - else - audioStream = new DummyMediaStream("dummyAudio"); - - if (stream && stream.videoStream) - videoStream = stream.videoStream; - else - videoStream = new DummyMediaStream("dummyVideo"); - } - - var audioMuted = (usageOptions && usageOptions.audio === false), - videoMuted = (usageOptions && usageOptions.video === false); - - var audioGUM = (!usageOptions || usageOptions.audio !== false), - videoGUM = (!usageOptions || usageOptions.video !== false); - - - this.service.createLocalStream(audioStream, "audio", null, null, - audioMuted, audioGUM); - - this.service.createLocalStream(videoStream, "video", null, null, - videoMuted, videoGUM); -}; - -function DummyMediaStream(id) { - this.id = id; - this.label = id; - this.stop = function() { }; - this.getAudioTracks = function() { return []; } - this.getVideoTracks = function() { return []; } -} - -RTCUtils.prototype.createStream = function(stream, isVideo) { - var newStream = null; - if (window.webkitMediaStream) { - newStream = new webkitMediaStream(); - if (newStream) { - var tracks = (isVideo ? stream.getVideoTracks() : stream.getAudioTracks()); - - for (i = 0; i < tracks.length; i++) { - newStream.addTrack(tracks[i]); - } - } - - } - else { - // FIXME: this is duplicated with 'handleLocalStream' !!! - if (stream) { - newStream = stream; - } else { - newStream = new DummyMediaStream(isVideo ? "dummyVideo" : "dummyAudio"); - } - } - - return newStream; -}; - -module.exports = RTCUtils; - -},{"../../service/RTC/Resolutions":102,"../xmpp/SDPUtil":58,"./RTCBrowserType":10,"./adapter.screenshare":12}],12:[function(require,module,exports){ -/*! adapterjs - v0.11.0 - 2015-06-08 */ - -// Adapter's interface. -var AdapterJS = AdapterJS || {}; - -// Browserify compatibility -if(typeof exports !== 'undefined') { - module.exports = AdapterJS; -} - -AdapterJS.options = AdapterJS.options || {}; - -// uncomment to get virtual webcams -// AdapterJS.options.getAllCams = true; - -// uncomment to prevent the install prompt when the plugin in not yet installed -// AdapterJS.options.hidePluginInstallPrompt = true; - -// AdapterJS version -AdapterJS.VERSION = '0.11.0'; - -// This function will be called when the WebRTC API is ready to be used -// Whether it is the native implementation (Chrome, Firefox, Opera) or -// the plugin -// You may Override this function to synchronise the start of your application -// with the WebRTC API being ready. -// If you decide not to override use this synchronisation, it may result in -// an extensive CPU usage on the plugin start (once per tab loaded) -// Params: -// - isUsingPlugin: true is the WebRTC plugin is being used, false otherwise -// -AdapterJS.onwebrtcready = AdapterJS.onwebrtcready || function(isUsingPlugin) { - // The WebRTC API is ready. - // Override me and do whatever you want here -}; - -// Sets a callback function to be called when the WebRTC interface is ready. -// The first argument is the function to callback.\ -// Throws an error if the first argument is not a function -AdapterJS.webRTCReady = function (callback) { - if (typeof callback !== 'function') { - throw new Error('Callback provided is not a function'); - } - - if (true === AdapterJS.onwebrtcreadyDone) { - // All WebRTC interfaces are ready, just call the callback - callback(null !== AdapterJS.WebRTCPlugin.plugin); - } else { - // will be triggered automatically when your browser/plugin is ready. - AdapterJS.onwebrtcready = callback; - } -}; - -// Plugin namespace -AdapterJS.WebRTCPlugin = AdapterJS.WebRTCPlugin || {}; - -// The object to store plugin information -AdapterJS.WebRTCPlugin.pluginInfo = { - prefix : 'Tem', - plugName : 'TemWebRTCPlugin', - pluginId : 'plugin0', - type : 'application/x-temwebrtcplugin', - onload : '__TemWebRTCReady0', - portalLink : 'http://skylink.io/plugin/', - downloadLink : null, //set below - companyName: 'Temasys' -}; -if(!!navigator.platform.match(/^Mac/i)) { - AdapterJS.WebRTCPlugin.pluginInfo.downloadLink = 'http://bit.ly/1n77hco'; -} -else if(!!navigator.platform.match(/^Win/i)) { - AdapterJS.WebRTCPlugin.pluginInfo.downloadLink = 'http://bit.ly/1kkS4FN'; -} - -// Unique identifier of each opened page -AdapterJS.WebRTCPlugin.pageId = Math.random().toString(36).slice(2); - -// Use this whenever you want to call the plugin. -AdapterJS.WebRTCPlugin.plugin = null; - -// Set log level for the plugin once it is ready. -// The different values are -// This is an asynchronous function that will run when the plugin is ready -AdapterJS.WebRTCPlugin.setLogLevel = null; - -// Defines webrtc's JS interface according to the plugin's implementation. -// Define plugin Browsers as WebRTC Interface. -AdapterJS.WebRTCPlugin.defineWebRTCInterface = null; - -// This function detects whether or not a plugin is installed. -// Checks if Not IE (firefox, for example), else if it's IE, -// we're running IE and do something. If not it is not supported. -AdapterJS.WebRTCPlugin.isPluginInstalled = null; - - // Lets adapter.js wait until the the document is ready before injecting the plugin -AdapterJS.WebRTCPlugin.pluginInjectionInterval = null; - -// Inject the HTML DOM object element into the page. -AdapterJS.WebRTCPlugin.injectPlugin = null; - -// States of readiness that the plugin goes through when -// being injected and stated -AdapterJS.WebRTCPlugin.PLUGIN_STATES = { - NONE : 0, // no plugin use - INITIALIZING : 1, // Detected need for plugin - INJECTING : 2, // Injecting plugin - INJECTED: 3, // Plugin element injected but not usable yet - READY: 4 // Plugin ready to be used -}; - -// Current state of the plugin. You cannot use the plugin before this is -// equal to AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY -AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.NONE; - -// True is AdapterJS.onwebrtcready was already called, false otherwise -// Used to make sure AdapterJS.onwebrtcready is only called once -AdapterJS.onwebrtcreadyDone = false; - -// Log levels for the plugin. -// To be set by calling AdapterJS.WebRTCPlugin.setLogLevel -/* -Log outputs are prefixed in some cases. - INFO: Information reported by the plugin. - ERROR: Errors originating from within the plugin. - WEBRTC: Error originating from within the libWebRTC library -*/ -// From the least verbose to the most verbose -AdapterJS.WebRTCPlugin.PLUGIN_LOG_LEVELS = { - NONE : 'NONE', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO: 'INFO', - VERBOSE: 'VERBOSE', - SENSITIVE: 'SENSITIVE' -}; - -// Does a waiting check before proceeding to load the plugin. -AdapterJS.WebRTCPlugin.WaitForPluginReady = null; - -// This methid will use an interval to wait for the plugin to be ready. -AdapterJS.WebRTCPlugin.callWhenPluginReady = null; - -// !!!! WARNING: DO NOT OVERRIDE THIS FUNCTION. !!! -// This function will be called when plugin is ready. It sends necessary -// details to the plugin. -// The function will wait for the document to be ready and the set the -// plugin state to AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY, -// indicating that it can start being requested. -// This function is not in the IE/Safari condition brackets so that -// TemPluginLoaded function might be called on Chrome/Firefox. -// This function is the only private function that is not encapsulated to -// allow the plugin method to be called. -__TemWebRTCReady0 = function () { - if (document.readyState === 'complete') { - AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY; - - AdapterJS.maybeThroughWebRTCReady(); - } else { - AdapterJS.WebRTCPlugin.documentReadyInterval = setInterval(function () { - if (document.readyState === 'complete') { - // TODO: update comments, we wait for the document to be ready - clearInterval(AdapterJS.WebRTCPlugin.documentReadyInterval); - AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY; - - AdapterJS.maybeThroughWebRTCReady(); - } - }, 100); - } -}; - -AdapterJS.maybeThroughWebRTCReady = function() { - if (!AdapterJS.onwebrtcreadyDone) { - AdapterJS.onwebrtcreadyDone = true; - - if (typeof(AdapterJS.onwebrtcready) === 'function') { - AdapterJS.onwebrtcready(AdapterJS.WebRTCPlugin.plugin !== null); - } - } -}; - -// Text namespace -AdapterJS.TEXT = { - PLUGIN: { - REQUIRE_INSTALLATION: 'This website requires you to install a WebRTC-enabling plugin ' + - 'to work on this browser.', - NOT_SUPPORTED: 'Your browser does not support WebRTC.', - BUTTON: 'Install Now' - }, - REFRESH: { - REQUIRE_REFRESH: 'Please refresh page', - BUTTON: 'Refresh Page' - } -}; - -// The result of ice connection states. -// - starting: Ice connection is starting. -// - checking: Ice connection is checking. -// - connected Ice connection is connected. -// - completed Ice connection is connected. -// - done Ice connection has been completed. -// - disconnected Ice connection has been disconnected. -// - failed Ice connection has failed. -// - closed Ice connection is closed. -AdapterJS._iceConnectionStates = { - starting : 'starting', - checking : 'checking', - connected : 'connected', - completed : 'connected', - done : 'completed', - disconnected : 'disconnected', - failed : 'failed', - closed : 'closed' -}; - -//The IceConnection states that has been fired for each peer. -AdapterJS._iceConnectionFiredStates = []; - - -// Check if WebRTC Interface is defined. -AdapterJS.isDefined = null; - -// This function helps to retrieve the webrtc detected browser information. -// This sets: -// - webrtcDetectedBrowser: The browser agent name. -// - webrtcDetectedVersion: The browser version. -// - webrtcDetectedType: The types of webRTC support. -// - 'moz': Mozilla implementation of webRTC. -// - 'webkit': WebKit implementation of webRTC. -// - 'plugin': Using the plugin implementation. -AdapterJS.parseWebrtcDetectedBrowser = function () { - var hasMatch, checkMatch = navigator.userAgent.match( - /(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; - if (/trident/i.test(checkMatch[1])) { - hasMatch = /\brv[ :]+(\d+)/g.exec(navigator.userAgent) || []; - webrtcDetectedBrowser = 'IE'; - webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10); - } else if (checkMatch[1] === 'Chrome') { - hasMatch = navigator.userAgent.match(/\bOPR\/(\d+)/); - if (hasMatch !== null) { - webrtcDetectedBrowser = 'opera'; - webrtcDetectedVersion = parseInt(hasMatch[1], 10); - } - } - if (navigator.userAgent.indexOf('Safari')) { - if (typeof InstallTrigger !== 'undefined') { - webrtcDetectedBrowser = 'firefox'; - } else if (/*@cc_on!@*/ false || !!document.documentMode) { - webrtcDetectedBrowser = 'IE'; - } else if ( - Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) { - webrtcDetectedBrowser = 'safari'; - } else if (!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0) { - webrtcDetectedBrowser = 'opera'; - } else if (!!window.chrome) { - webrtcDetectedBrowser = 'chrome'; - } - } - if (!webrtcDetectedBrowser) { - webrtcDetectedVersion = checkMatch[1]; - } - if (!webrtcDetectedVersion) { - try { - checkMatch = (checkMatch[2]) ? [checkMatch[1], checkMatch[2]] : - [navigator.appName, navigator.appVersion, '-?']; - if ((hasMatch = navigator.userAgent.match(/version\/(\d+)/i)) !== null) { - checkMatch.splice(1, 1, hasMatch[1]); - } - webrtcDetectedVersion = parseInt(checkMatch[1], 10); - } catch (error) { } - } -}; - -// To fix configuration as some browsers does not support -// the 'urls' attribute. -AdapterJS.maybeFixConfiguration = function (pcConfig) { - if (pcConfig === null) { - return; - } - for (var i = 0; i < pcConfig.iceServers.length; i++) { - if (pcConfig.iceServers[i].hasOwnProperty('urls')) { - pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls; - delete pcConfig.iceServers[i].urls; - } - } -}; - -AdapterJS.addEvent = function(elem, evnt, func) { - if (elem.addEventListener) { // W3C DOM - elem.addEventListener(evnt, func, false); - } else if (elem.attachEvent) {// OLD IE DOM - elem.attachEvent('on'+evnt, func); - } else { // No much to do - elem[evnt] = func; - } -}; - -AdapterJS.renderNotificationBar = function (text, buttonText, buttonLink, openNewTab, displayRefreshBar) { - // only inject once the page is ready - if (document.readyState !== 'complete') { - return; - } - - var w = window; - var i = document.createElement('iframe'); - i.style.position = 'fixed'; - i.style.top = '-41px'; - i.style.left = 0; - i.style.right = 0; - i.style.width = '100%'; - i.style.height = '40px'; - i.style.backgroundColor = '#ffffe1'; - i.style.border = 'none'; - i.style.borderBottom = '1px solid #888888'; - i.style.zIndex = '9999999'; - if(typeof i.style.webkitTransition === 'string') { - i.style.webkitTransition = 'all .5s ease-out'; - } else if(typeof i.style.transition === 'string') { - i.style.transition = 'all .5s ease-out'; - } - document.body.appendChild(i); - c = (i.contentWindow) ? i.contentWindow : - (i.contentDocument.document) ? i.contentDocument.document : i.contentDocument; - c.document.open(); - c.document.write('' + text + ''); - if(buttonText && buttonLink) { - c.document.write(''); - c.document.close(); - - AdapterJS.addEvent(c.document.getElementById('okay'), 'click', function(e) { - if (!!displayRefreshBar) { - AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION ? - AdapterJS.TEXT.EXTENSION.REQUIRE_REFRESH : AdapterJS.TEXT.REFRESH.REQUIRE_REFRESH, - AdapterJS.TEXT.REFRESH.BUTTON, 'javascript:location.reload()'); - } - window.open(buttonLink, !!openNewTab ? '_blank' : '_top'); - - e.preventDefault(); - try { - event.cancelBubble = true; - } catch(error) { } - }); - } - else { - c.document.close(); - } - AdapterJS.addEvent(c.document, 'click', function() { - w.document.body.removeChild(i); - }); - setTimeout(function() { - if(typeof i.style.webkitTransform === 'string') { - i.style.webkitTransform = 'translateY(40px)'; - } else if(typeof i.style.transform === 'string') { - i.style.transform = 'translateY(40px)'; - } else { - i.style.top = '0px'; - } - }, 300); -}; - -// ----------------------------------------------------------- -// Detected webrtc implementation. Types are: -// - 'moz': Mozilla implementation of webRTC. -// - 'webkit': WebKit implementation of webRTC. -// - 'plugin': Using the plugin implementation. -webrtcDetectedType = null; - -// Detected webrtc datachannel support. Types are: -// - 'SCTP': SCTP datachannel support. -// - 'RTP': RTP datachannel support. -webrtcDetectedDCSupport = null; - -// Set the settings for creating DataChannels, MediaStream for -// Cross-browser compability. -// - This is only for SCTP based support browsers. -// the 'urls' attribute. -checkMediaDataChannelSettings = - function (peerBrowserAgent, peerBrowserVersion, callback, constraints) { - if (typeof callback !== 'function') { - return; - } - var beOfferer = true; - var isLocalFirefox = webrtcDetectedBrowser === 'firefox'; - // Nightly version does not require MozDontOfferDataChannel for interop - var isLocalFirefoxInterop = webrtcDetectedType === 'moz' && webrtcDetectedVersion > 30; - var isPeerFirefox = peerBrowserAgent === 'firefox'; - var isPeerFirefoxInterop = peerBrowserAgent === 'firefox' && - ((peerBrowserVersion) ? (peerBrowserVersion > 30) : false); - - // Resends an updated version of constraints for MozDataChannel to work - // If other userAgent is firefox and user is firefox, remove MozDataChannel - if ((isLocalFirefox && isPeerFirefox) || (isLocalFirefoxInterop)) { - try { - delete constraints.mandatory.MozDontOfferDataChannel; - } catch (error) { - console.error('Failed deleting MozDontOfferDataChannel'); - console.error(error); - } - } else if ((isLocalFirefox && !isPeerFirefox)) { - constraints.mandatory.MozDontOfferDataChannel = true; - } - if (!isLocalFirefox) { - // temporary measure to remove Moz* constraints in non Firefox browsers - for (var prop in constraints.mandatory) { - if (constraints.mandatory.hasOwnProperty(prop)) { - if (prop.indexOf('Moz') !== -1) { - delete constraints.mandatory[prop]; - } - } - } - } - // Firefox (not interopable) cannot offer DataChannel as it will cause problems to the - // interopability of the media stream - if (isLocalFirefox && !isPeerFirefox && !isLocalFirefoxInterop) { - beOfferer = false; - } - callback(beOfferer, constraints); -}; - -// Handles the differences for all browsers ice connection state output. -// - Tested outcomes are: -// - Chrome (offerer) : 'checking' > 'completed' > 'completed' -// - Chrome (answerer) : 'checking' > 'connected' -// - Firefox (offerer) : 'checking' > 'connected' -// - Firefox (answerer): 'checking' > 'connected' -checkIceConnectionState = function (peerId, iceConnectionState, callback) { - if (typeof callback !== 'function') { - console.warn('No callback specified in checkIceConnectionState. Aborted.'); - return; - } - peerId = (peerId) ? peerId : 'peer'; - - if (!AdapterJS._iceConnectionFiredStates[peerId] || - iceConnectionState === AdapterJS._iceConnectionStates.disconnected || - iceConnectionState === AdapterJS._iceConnectionStates.failed || - iceConnectionState === AdapterJS._iceConnectionStates.closed) { - AdapterJS._iceConnectionFiredStates[peerId] = []; - } - iceConnectionState = AdapterJS._iceConnectionStates[iceConnectionState]; - if (AdapterJS._iceConnectionFiredStates[peerId].indexOf(iceConnectionState) < 0) { - AdapterJS._iceConnectionFiredStates[peerId].push(iceConnectionState); - if (iceConnectionState === AdapterJS._iceConnectionStates.connected) { - setTimeout(function () { - AdapterJS._iceConnectionFiredStates[peerId] - .push(AdapterJS._iceConnectionStates.done); - callback(AdapterJS._iceConnectionStates.done); - }, 1000); - } - callback(iceConnectionState); - } - return; -}; - -// Firefox: -// - Creates iceServer from the url for Firefox. -// - Create iceServer with stun url. -// - Create iceServer with turn url. -// - Ignore the transport parameter from TURN url for FF version <=27. -// - Return null for createIceServer if transport=tcp. -// - FF 27 and above supports transport parameters in TURN url, -// - So passing in the full url to create iceServer. -// Chrome: -// - Creates iceServer from the url for Chrome M33 and earlier. -// - Create iceServer with stun url. -// - Chrome M28 & above uses below TURN format. -// Plugin: -// - Creates Ice Server for Plugin Browsers -// - If Stun - Create iceServer with stun url. -// - Else - Create iceServer with turn url -// - This is a WebRTC Function -createIceServer = null; - -// Firefox: -// - Creates IceServers for Firefox -// - Use .url for FireFox. -// - Multiple Urls support -// Chrome: -// - Creates iceServers from the urls for Chrome M34 and above. -// - .urls is supported since Chrome M34. -// - Multiple Urls support -// Plugin: -// - Creates Ice Servers for Plugin Browsers -// - Multiple Urls support -// - This is a WebRTC Function -createIceServers = null; -//------------------------------------------------------------ - -//The RTCPeerConnection object. -RTCPeerConnection = null; - -// Creates RTCSessionDescription object for Plugin Browsers -RTCSessionDescription = (typeof RTCSessionDescription === 'function') ? - RTCSessionDescription : null; - -// Creates RTCIceCandidate object for Plugin Browsers -RTCIceCandidate = (typeof RTCIceCandidate === 'function') ? - RTCIceCandidate : null; - -// Get UserMedia (only difference is the prefix). -// Code from Adam Barth. -getUserMedia = null; - -// Attach a media stream to an element. -attachMediaStream = null; - -// Re-attach a media stream to an element. -reattachMediaStream = null; - - -// Detected browser agent name. Types are: -// - 'firefox': Firefox browser. -// - 'chrome': Chrome browser. -// - 'opera': Opera browser. -// - 'safari': Safari browser. -// - 'IE' - Internet Explorer browser. -webrtcDetectedBrowser = null; - -// Detected browser version. -webrtcDetectedVersion = null; - -// Check for browser types and react accordingly -if (navigator.mozGetUserMedia) { - webrtcDetectedBrowser = 'firefox'; - webrtcDetectedVersion = parseInt(navigator - .userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); - webrtcDetectedType = 'moz'; - webrtcDetectedDCSupport = 'SCTP'; - - RTCPeerConnection = function (pcConfig, pcConstraints) { - AdapterJS.maybeFixConfiguration(pcConfig); - return new mozRTCPeerConnection(pcConfig, pcConstraints); - }; - - // The RTCSessionDescription object. - RTCSessionDescription = mozRTCSessionDescription; - window.RTCSessionDescription = RTCSessionDescription; - - // The RTCIceCandidate object. - RTCIceCandidate = mozRTCIceCandidate; - window.RTCIceCandidate = RTCIceCandidate; - - window.getUserMedia = navigator.mozGetUserMedia.bind(navigator); - navigator.getUserMedia = window.getUserMedia; - - // Shim for MediaStreamTrack.getSources. - MediaStreamTrack.getSources = function(successCb) { - setTimeout(function() { - var infos = [ - { kind: 'audio', id: 'default', label:'', facing:'' }, - { kind: 'video', id: 'default', label:'', facing:'' } - ]; - successCb(infos); - }, 0); - }; - - createIceServer = function (url, username, password) { - var iceServer = null; - var url_parts = url.split(':'); - if (url_parts[0].indexOf('stun') === 0) { - iceServer = { url : url }; - } else if (url_parts[0].indexOf('turn') === 0) { - if (webrtcDetectedVersion < 27) { - var turn_url_parts = url.split('?'); - if (turn_url_parts.length === 1 || - turn_url_parts[1].indexOf('transport=udp') === 0) { - iceServer = { - url : turn_url_parts[0], - credential : password, - username : username - }; - } - } else { - iceServer = { - url : url, - credential : password, - username : username - }; - } - } - return iceServer; - }; - - createIceServers = function (urls, username, password) { - var iceServers = []; - for (i = 0; i < urls.length; i++) { - var iceServer = createIceServer(urls[i], username, password); - if (iceServer !== null) { - iceServers.push(iceServer); - } - } - return iceServers; - }; - - attachMediaStream = function (element, stream) { - element.mozSrcObject = stream; - if (stream !== null) - element.play(); - - return element; - }; - - reattachMediaStream = function (to, from) { - to.mozSrcObject = from.mozSrcObject; - to.play(); - return to; - }; - - MediaStreamTrack.getSources = MediaStreamTrack.getSources || function (callback) { - if (!callback) { - throw new TypeError('Failed to execute \'getSources\' on \'MediaStreamTrack\'' + - ': 1 argument required, but only 0 present.'); - } - return callback([]); - }; - - // Fake get{Video,Audio}Tracks - if (!MediaStream.prototype.getVideoTracks) { - MediaStream.prototype.getVideoTracks = function () { - return []; - }; - } - if (!MediaStream.prototype.getAudioTracks) { - MediaStream.prototype.getAudioTracks = function () { - return []; - }; - } - - AdapterJS.maybeThroughWebRTCReady(); -} else if (navigator.webkitGetUserMedia) { - webrtcDetectedBrowser = 'chrome'; - webrtcDetectedType = 'webkit'; - webrtcDetectedVersion = parseInt(navigator - .userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); - // check if browser is opera 20+ - var checkIfOpera = navigator.userAgent.match(/\bOPR\/(\d+)/); - if (checkIfOpera !== null) { - webrtcDetectedBrowser = 'opera'; - webrtcDetectedVersion = parseInt(checkIfOpera[1], 10); - } - // check browser datachannel support - if ((webrtcDetectedBrowser === 'chrome' && webrtcDetectedVersion >= 31) || - (webrtcDetectedBrowser === 'opera' && webrtcDetectedVersion >= 20)) { - webrtcDetectedDCSupport = 'SCTP'; - } else if (webrtcDetectedBrowser === 'chrome' && webrtcDetectedVersion < 30 && - webrtcDetectedVersion > 24) { - webrtcDetectedDCSupport = 'RTP'; - } else { - webrtcDetectedDCSupport = ''; - } - - createIceServer = function (url, username, password) { - var iceServer = null; - var url_parts = url.split(':'); - if (url_parts[0].indexOf('stun') === 0) { - iceServer = { 'url' : url }; - } else if (url_parts[0].indexOf('turn') === 0) { - iceServer = { - 'url' : url, - 'credential' : password, - 'username' : username - }; - } - return iceServer; - }; - - createIceServers = function (urls, username, password) { - var iceServers = []; - if (webrtcDetectedVersion >= 34) { - iceServers = { - 'urls' : urls, - 'credential' : password, - 'username' : username - }; - } else { - for (i = 0; i < urls.length; i++) { - var iceServer = createIceServer(urls[i], username, password); - if (iceServer !== null) { - iceServers.push(iceServer); - } - } - } - return iceServers; - }; - - RTCPeerConnection = function (pcConfig, pcConstraints) { - if (webrtcDetectedVersion < 34) { - AdapterJS.maybeFixConfiguration(pcConfig); - } - return new webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - - window.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - navigator.getUserMedia = window.getUserMedia; - - attachMediaStream = function (element, stream) { - if (typeof element.srcObject !== 'undefined') { - element.srcObject = stream; - } else if (typeof element.mozSrcObject !== 'undefined') { - element.mozSrcObject = stream; - } else if (typeof element.src !== 'undefined') { - element.src = (stream === null ? '' : URL.createObjectURL(stream)); - } else { - console.log('Error attaching stream to element.'); - } - return element; - }; - - reattachMediaStream = function (to, from) { - to.src = from.src; - return to; - }; - - AdapterJS.maybeThroughWebRTCReady(); -} else { // TRY TO USE PLUGIN - // IE 9 is not offering an implementation of console.log until you open a console - if (typeof console !== 'object' || typeof console.log !== 'function') { - /* jshint -W020 */ - console = {} || console; - // Implemented based on console specs from MDN - // You may override these functions - console.log = function (arg) {}; - console.info = function (arg) {}; - console.error = function (arg) {}; - console.dir = function (arg) {}; - console.exception = function (arg) {}; - console.trace = function (arg) {}; - console.warn = function (arg) {}; - console.count = function (arg) {}; - console.debug = function (arg) {}; - console.count = function (arg) {}; - console.time = function (arg) {}; - console.timeEnd = function (arg) {}; - console.group = function (arg) {}; - console.groupCollapsed = function (arg) {}; - console.groupEnd = function (arg) {}; - /* jshint +W020 */ - } - webrtcDetectedType = 'plugin'; - webrtcDetectedDCSupport = 'plugin'; - AdapterJS.parseWebrtcDetectedBrowser(); - isIE = webrtcDetectedBrowser === 'IE'; - - /* jshint -W035 */ - AdapterJS.WebRTCPlugin.WaitForPluginReady = function() { - while (AdapterJS.WebRTCPlugin.pluginState !== AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) { - /* empty because it needs to prevent the function from running. */ - } - }; - /* jshint +W035 */ - - AdapterJS.WebRTCPlugin.callWhenPluginReady = function (callback) { - if (AdapterJS.WebRTCPlugin.pluginState === AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) { - // Call immediately if possible - // Once the plugin is set, the code will always take this path - callback(); - } else { - // otherwise start a 100ms interval - var checkPluginReadyState = setInterval(function () { - if (AdapterJS.WebRTCPlugin.pluginState === AdapterJS.WebRTCPlugin.PLUGIN_STATES.READY) { - clearInterval(checkPluginReadyState); - callback(); - } - }, 100); - } - }; - - AdapterJS.WebRTCPlugin.setLogLevel = function(logLevel) { - AdapterJS.WebRTCPlugin.callWhenPluginReady(function() { - AdapterJS.WebRTCPlugin.plugin.setLogLevel(logLevel); - }); - }; - - AdapterJS.WebRTCPlugin.injectPlugin = function () { - // only inject once the page is ready - if (document.readyState !== 'complete') { - return; - } - - // Prevent multiple injections - if (AdapterJS.WebRTCPlugin.pluginState !== AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING) { - return; - } - - AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTING; - - if (webrtcDetectedBrowser === 'IE' && webrtcDetectedVersion <= 10) { - var frag = document.createDocumentFragment(); - AdapterJS.WebRTCPlugin.plugin = document.createElement('div'); - AdapterJS.WebRTCPlugin.plugin.innerHTML = '' + - ' ' + - ' ' + - ' ' + - '' + - // uncomment to be able to use virtual cams - (AdapterJS.options.getAllCams ? '':'') + - - ''; - while (AdapterJS.WebRTCPlugin.plugin.firstChild) { - frag.appendChild(AdapterJS.WebRTCPlugin.plugin.firstChild); - } - document.body.appendChild(frag); - - // Need to re-fetch the plugin - AdapterJS.WebRTCPlugin.plugin = - document.getElementById(AdapterJS.WebRTCPlugin.pluginInfo.pluginId); - } else { - // Load Plugin - AdapterJS.WebRTCPlugin.plugin = document.createElement('object'); - AdapterJS.WebRTCPlugin.plugin.id = - AdapterJS.WebRTCPlugin.pluginInfo.pluginId; - // IE will only start the plugin if it's ACTUALLY visible - if (isIE) { - AdapterJS.WebRTCPlugin.plugin.width = '1px'; - AdapterJS.WebRTCPlugin.plugin.height = '1px'; - } else { // The size of the plugin on Safari should be 0x0px - // so that the autorisation prompt is at the top - AdapterJS.WebRTCPlugin.plugin.width = '0px'; - AdapterJS.WebRTCPlugin.plugin.height = '0px'; - } - AdapterJS.WebRTCPlugin.plugin.type = AdapterJS.WebRTCPlugin.pluginInfo.type; - AdapterJS.WebRTCPlugin.plugin.innerHTML = '' + - '' + - ' ' + - (AdapterJS.options.getAllCams ? '':'') + - ''; - document.body.appendChild(AdapterJS.WebRTCPlugin.plugin); - } - - - AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INJECTED; - }; - - AdapterJS.WebRTCPlugin.isPluginInstalled = - function (comName, plugName, installedCb, notInstalledCb) { - if (!isIE) { - var pluginArray = navigator.plugins; - for (var i = 0; i < pluginArray.length; i++) { - if (pluginArray[i].name.indexOf(plugName) >= 0) { - installedCb(); - return; - } - } - notInstalledCb(); - } else { - try { - var axo = new ActiveXObject(comName + '.' + plugName); - } catch (e) { - notInstalledCb(); - return; - } - installedCb(); - } - }; - - AdapterJS.WebRTCPlugin.defineWebRTCInterface = function () { - AdapterJS.WebRTCPlugin.pluginState = AdapterJS.WebRTCPlugin.PLUGIN_STATES.INITIALIZING; - - AdapterJS.isDefined = function (variable) { - return variable !== null && variable !== undefined; - }; - - createIceServer = function (url, username, password) { - var iceServer = null; - var url_parts = url.split(':'); - if (url_parts[0].indexOf('stun') === 0) { - iceServer = { - 'url' : url, - 'hasCredentials' : false - }; - } else if (url_parts[0].indexOf('turn') === 0) { - iceServer = { - 'url' : url, - 'hasCredentials' : true, - 'credential' : password, - 'username' : username - }; - } - return iceServer; - }; - - createIceServers = function (urls, username, password) { - var iceServers = []; - for (var i = 0; i < urls.length; ++i) { - iceServers.push(createIceServer(urls[i], username, password)); - } - return iceServers; - }; - - RTCSessionDescription = function (info) { - AdapterJS.WebRTCPlugin.WaitForPluginReady(); - return AdapterJS.WebRTCPlugin.plugin. - ConstructSessionDescription(info.type, info.sdp); - }; - - RTCPeerConnection = function (servers, constraints) { - var iceServers = null; - if (servers) { - iceServers = servers.iceServers; - for (var i = 0; i < iceServers.length; i++) { - if (iceServers[i].urls && !iceServers[i].url) { - iceServers[i].url = iceServers[i].urls; - } - iceServers[i].hasCredentials = AdapterJS. - isDefined(iceServers[i].username) && - AdapterJS.isDefined(iceServers[i].credential); - } - } - var mandatory = (constraints && constraints.mandatory) ? - constraints.mandatory : null; - var optional = (constraints && constraints.optional) ? - constraints.optional : null; - - AdapterJS.WebRTCPlugin.WaitForPluginReady(); - return AdapterJS.WebRTCPlugin.plugin. - PeerConnection(AdapterJS.WebRTCPlugin.pageId, - iceServers, mandatory, optional); - }; - - MediaStreamTrack = {}; - MediaStreamTrack.getSources = function (callback) { - AdapterJS.WebRTCPlugin.callWhenPluginReady(function() { - AdapterJS.WebRTCPlugin.plugin.GetSources(callback); - }); - }; - - window.getUserMedia = function (constraints, successCallback, failureCallback) { - constraints.audio = constraints.audio || false; - constraints.video = constraints.video || false; - - AdapterJS.WebRTCPlugin.callWhenPluginReady(function() { - AdapterJS.WebRTCPlugin.plugin. - getUserMedia(constraints, successCallback, failureCallback); - }); - }; - window.navigator.getUserMedia = window.getUserMedia; - - attachMediaStream = function (element, stream) { - if (!element || !element.parentNode) { - return; - } - - var streamId - if (stream === null) { - streamId = ''; - } - else { - stream.enableSoundTracks(true); - streamId = stream.id; - } - - if (element.nodeName.toLowerCase() !== 'audio') { - var elementId = element.id.length === 0 ? Math.random().toString(36).slice(2) : element.id; - if (!element.isWebRTCPlugin || !element.isWebRTCPlugin()) { - var frag = document.createDocumentFragment(); - var temp = document.createElement('div'); - var classHTML = ''; - if (element.className) { - classHTML = 'class="' + element.className + '" '; - } else if (element.attributes && element.attributes['class']) { - classHTML = 'class="' + element.attributes['class'].value + '" '; - } - - temp.innerHTML = '' + - ' ' + - ' ' + - ' ' + - ' ' + - ''; - while (temp.firstChild) { - frag.appendChild(temp.firstChild); - } - - var height = ''; - var width = ''; - if (element.getBoundingClientRect) { - var rectObject = element.getBoundingClientRect(); - width = rectObject.width + 'px'; - height = rectObject.height + 'px'; - } - else if (element.width) { - width = element.width; - height = element.height; - } else { - // TODO: What scenario could bring us here? - } - - element.parentNode.insertBefore(frag, element); - frag = document.getElementById(elementId); - frag.width = width; - frag.height = height; - element.parentNode.removeChild(element); - } else { - var children = element.children; - for (var i = 0; i !== children.length; ++i) { - if (children[i].name === 'streamId') { - children[i].value = streamId; - break; - } - } - element.setStreamId(streamId); - } - var newElement = document.getElementById(elementId); - newElement.onplaying = (element.onplaying) ? element.onplaying : function (arg) {}; - if (isIE) { // on IE the event needs to be plugged manually - newElement.attachEvent('onplaying', newElement.onplaying); - newElement.onclick = (element.onclick) ? element.onclick : function (arg) {}; - newElement._TemOnClick = function (id) { - var arg = { - srcElement : document.getElementById(id) - }; - newElement.onclick(arg); - }; - } - return newElement; - } else { - return element; - } - }; - - reattachMediaStream = function (to, from) { - var stream = null; - var children = from.children; - for (var i = 0; i !== children.length; ++i) { - if (children[i].name === 'streamId') { - AdapterJS.WebRTCPlugin.WaitForPluginReady(); - stream = AdapterJS.WebRTCPlugin.plugin - .getStreamWithId(AdapterJS.WebRTCPlugin.pageId, children[i].value); - break; - } - } - if (stream !== null) { - return attachMediaStream(to, stream); - } else { - console.log('Could not find the stream associated with this element'); - } - }; - - RTCIceCandidate = function (candidate) { - if (!candidate.sdpMid) { - candidate.sdpMid = ''; - } - - AdapterJS.WebRTCPlugin.WaitForPluginReady(); - return AdapterJS.WebRTCPlugin.plugin.ConstructIceCandidate( - candidate.sdpMid, candidate.sdpMLineIndex, candidate.candidate - ); - }; - - // inject plugin - AdapterJS.addEvent(document, 'readystatechange', AdapterJS.WebRTCPlugin.injectPlugin); - AdapterJS.WebRTCPlugin.injectPlugin(); - }; - - // This function will be called if the plugin is needed (browser different - // from Chrome or Firefox), but the plugin is not installed. - AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb = AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb || - function() { - AdapterJS.addEvent(document, - 'readystatechange', - AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv); - AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv(); - }; - - AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCbPriv = function () { - if (AdapterJS.options.hidePluginInstallPrompt) { - return; - } - - var downloadLink = AdapterJS.WebRTCPlugin.pluginInfo.downloadLink; - if(downloadLink) { // if download link - var popupString; - if (AdapterJS.WebRTCPlugin.pluginInfo.portalLink) { // is portal link - popupString = 'This website requires you to install the ' + - ' ' + AdapterJS.WebRTCPlugin.pluginInfo.companyName + - ' WebRTC Plugin' + - ' to work on this browser.'; - } else { // no portal link, just print a generic explanation - popupString = AdapterJS.TEXT.PLUGIN.REQUIRE_INSTALLATION; - } - - AdapterJS.renderNotificationBar(popupString, AdapterJS.TEXT.PLUGIN.BUTTON, downloadLink); - } else { // no download link, just print a generic explanation - AdapterJS.renderNotificationBar(AdapterJS.TEXT.PLUGIN.NOT_SUPPORTED); - } - }; - - // Try to detect the plugin and act accordingly - AdapterJS.WebRTCPlugin.isPluginInstalled( - AdapterJS.WebRTCPlugin.pluginInfo.prefix, - AdapterJS.WebRTCPlugin.pluginInfo.plugName, - AdapterJS.WebRTCPlugin.defineWebRTCInterface, - AdapterJS.WebRTCPlugin.pluginNeededButNotInstalledCb); -} - - - -(function () { - - 'use strict'; - - var baseGetUserMedia = null; - - AdapterJS.TEXT.EXTENSION = { - REQUIRE_INSTALLATION_FF: 'To enable screensharing you need to install the Skylink WebRTC tools Firefox Add-on.', - REQUIRE_INSTALLATION_CHROME: 'To enable screensharing you need to install the Skylink WebRTC tools Chrome Extension.', - REQUIRE_REFRESH: 'Please refresh this page after the Skylink WebRTC tools extension has been installed.', - BUTTON_FF: 'Install Now', - BUTTON_CHROME: 'Go to Chrome Web Store' - }; - - var clone = function(obj) { - if (null == obj || "object" != typeof obj) return obj; - var copy = obj.constructor(); - for (var attr in obj) { - if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; - } - return copy; - }; - - if (window.navigator.mozGetUserMedia) { - baseGetUserMedia = window.navigator.getUserMedia; - - navigator.getUserMedia = function (constraints, successCb, failureCb) { - - if (constraints && constraints.video && !!constraints.video.mediaSource) { - // intercepting screensharing requests - - if (constraints.video.mediaSource !== 'screen' && constraints.video.mediaSource !== 'window') { - throw new Error('Only "screen" and "window" option is available as mediaSource'); - } - - var updatedConstraints = clone(constraints); - - //constraints.video.mediaSource = constraints.video.mediaSource; - updatedConstraints.video.mozMediaSource = updatedConstraints.video.mediaSource; - - // so generally, it requires for document.readyState to be completed before the getUserMedia could be invoked. - // strange but this works anyway - var checkIfReady = setInterval(function () { - if (document.readyState === 'complete') { - clearInterval(checkIfReady); - - baseGetUserMedia(updatedConstraints, successCb, function (error) { - if (error.name === 'PermissionDeniedError' && window.parent.location.protocol === 'https:') { - AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_FF, - AdapterJS.TEXT.EXTENSION.BUTTON_FF, - 'http://skylink.io/screensharing/ff_addon.php?domain=' + window.location.hostname, false, true); - //window.location.href = 'http://skylink.io/screensharing/ff_addon.php?domain=' + window.location.hostname; - } else { - failureCb(error); - } - }); - } - }, 1); - - } else { // regular GetUserMediaRequest - baseGetUserMedia(constraints, successCb, failureCb); - } - }; - - getUserMedia = navigator.getUserMedia; - - } else if (window.navigator.webkitGetUserMedia) { - baseGetUserMedia = window.navigator.getUserMedia; - - navigator.getUserMedia = function (constraints, successCb, failureCb) { - - if (constraints && constraints.video && !!constraints.video.mediaSource) { - if (window.webrtcDetectedBrowser !== 'chrome') { - throw new Error('Current browser does not support screensharing'); - } - - // would be fine since no methods - var updatedConstraints = clone(constraints); - - var chromeCallback = function(error, sourceId) { - if(!error) { - updatedConstraints.video.mandatory = updatedConstraints.video.mandatory || {}; - updatedConstraints.video.mandatory.chromeMediaSource = 'desktop'; - updatedConstraints.video.mandatory.maxWidth = window.screen.width > 1920 ? window.screen.width : 1920; - updatedConstraints.video.mandatory.maxHeight = window.screen.height > 1080 ? window.screen.height : 1080; - - if (sourceId) { - updatedConstraints.video.mandatory.chromeMediaSourceId = sourceId; - } - - delete updatedConstraints.video.mediaSource; - - baseGetUserMedia(updatedConstraints, successCb, failureCb); - - } else { - if (error === 'permission-denied') { - throw new Error('Permission denied for screen retrieval'); - } else { - throw new Error('Failed retrieving selected screen'); - } - } - }; - - var onIFrameCallback = function (event) { - if (!event.data) { - return; - } - - if (event.data.chromeMediaSourceId) { - if (event.data.chromeMediaSourceId === 'PermissionDeniedError') { - chromeCallback('permission-denied'); - } else { - chromeCallback(null, event.data.chromeMediaSourceId); - } - } - - if (event.data.chromeExtensionStatus) { - if (event.data.chromeExtensionStatus === 'not-installed') { - AdapterJS.renderNotificationBar(AdapterJS.TEXT.EXTENSION.REQUIRE_INSTALLATION_CHROME, - AdapterJS.TEXT.EXTENSION.BUTTON_CHROME, - event.data.data, true, true); - } else { - chromeCallback(event.data.chromeExtensionStatus, null); - } - } - - // this event listener is no more needed - window.removeEventListener('message', onIFrameCallback); - }; - - window.addEventListener('message', onIFrameCallback); - - postFrameMessage({ - captureSourceId: true - }); - - } else { - baseGetUserMedia(constraints, successCb, failureCb); - } - }; - - getUserMedia = navigator.getUserMedia; - - } else { - baseGetUserMedia = window.navigator.getUserMedia; - - navigator.getUserMedia = function (constraints, successCb, failureCb) { - if (constraints && constraints.video && !!constraints.video.mediaSource) { - // would be fine since no methods - var updatedConstraints = clone(constraints); - - // wait for plugin to be ready - AdapterJS.WebRTCPlugin.callWhenPluginReady(function() { - // check if screensharing feature is available - if (!!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature && - !!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) { - - - // set the constraints - updatedConstraints.video.optional = updatedConstraints.video.optional || []; - updatedConstraints.video.optional.push({ - sourceId: AdapterJS.WebRTCPlugin.plugin.screensharingKey || 'Screensharing' - }); - - delete updatedConstraints.video.mediaSource; - } else { - throw new Error('Your WebRTC plugin does not support screensharing'); - } - baseGetUserMedia(updatedConstraints, successCb, failureCb); - }); - } else { - baseGetUserMedia(constraints, successCb, failureCb); - } - }; - - getUserMedia = window.navigator.getUserMedia; - } - - if (window.webrtcDetectedBrowser === 'chrome') { - var iframe = document.createElement('iframe'); - - iframe.onload = function() { - iframe.isLoaded = true; - }; - - iframe.src = 'https://cdn.temasys.com.sg/skylink/extensions/detectRTC.html'; - //'https://temasys-cdn.s3.amazonaws.com/skylink/extensions/detection-script-dev/detectRTC.html'; - iframe.style.display = 'none'; - - (document.body || document.documentElement).appendChild(iframe); - - var postFrameMessage = function (object) { - object = object || {}; - - if (!iframe.isLoaded) { - setTimeout(function () { - iframe.contentWindow.postMessage(object, '*'); - }, 100); - return; - } - - iframe.contentWindow.postMessage(object, '*'); - }; - } -})(); -},{}],13:[function(require,module,exports){ -var UI = {}; - -var VideoLayout = require("./videolayout/VideoLayout.js"); -var AudioLevels = require("./audio_levels/AudioLevels.js"); -var Prezi = require("./prezi/Prezi.js"); -var Etherpad = require("./etherpad/Etherpad.js"); -var Chat = require("./side_pannels/chat/Chat.js"); -var Toolbar = require("./toolbars/Toolbar"); -var ToolbarToggler = require("./toolbars/ToolbarToggler"); -var BottomToolbar = require("./toolbars/BottomToolbar"); -var ContactList = require("./side_pannels/contactlist/ContactList"); -var Avatar = require("./avatar/Avatar"); -var EventEmitter = require("events"); -var SettingsMenu = require("./side_pannels/settings/SettingsMenu"); -var Settings = require("./../settings/Settings"); -var PanelToggler = require("./side_pannels/SidePanelToggler"); -var RoomNameGenerator = require("./welcome_page/RoomnameGenerator"); -UI.messageHandler = require("./util/MessageHandler"); -var messageHandler = UI.messageHandler; -var Authentication = require("./authentication/Authentication"); -var UIUtil = require("./util/UIUtil"); -var NicknameHandler = require("./util/NicknameHandler"); -var CQEvents = require("../../service/connectionquality/CQEvents"); -var DesktopSharingEventTypes - = require("../../service/desktopsharing/DesktopSharingEventTypes"); -var RTCEvents = require("../../service/RTC/RTCEvents"); -var RTCBrowserType = require("../RTC/RTCBrowserType"); -var StreamEventTypes = require("../../service/RTC/StreamEventTypes"); -var XMPPEvents = require("../../service/xmpp/XMPPEvents"); -var UIEvents = require("../../service/UI/UIEvents"); -var MemberEvents = require("../../service/members/Events"); - -var eventEmitter = new EventEmitter(); -var roomName = null; - - -function promptDisplayName() { - var message = '

'; - message += APP.translation.translateString( - "dialog.displayNameRequired"); - message += '

' + - ''; - - var buttonTxt - = APP.translation.generateTranslationHTML("dialog.Ok"); - var buttons = []; - buttons.push({title: buttonTxt, value: "ok"}); - - messageHandler.openDialog(null, message, - true, - buttons, - function (e, v, m, f) { - if (v == "ok") { - var displayName = f.displayName; - if (displayName) { - VideoLayout.inputDisplayNameHandler(displayName); - return true; - } - } - e.preventDefault(); - }, - function () { - var form = $.prompt.getPrompt(); - var input = form.find("input[name='displayName']"); - input.focus(); - var button = form.find("button"); - button.attr("disabled", "disabled"); - input.keyup(function () { - if(!input.val()) - button.attr("disabled", "disabled"); - else - button.removeAttr("disabled"); - }); - } - ); -} - - -function notifyForInitialMute() -{ - messageHandler.notify(null, "notify.mutedTitle", "connected", - "notify.muted", null, {timeOut: 120000}); -} - -function setupPrezi() -{ - $("#reloadPresentationLink").click(function() - { - Prezi.reloadPresentation(); - }); -} - -function setupChat() -{ - Chat.init(); - $("#toggle_smileys").click(function() { - Chat.toggleSmileys(); - }); -} - -function setupToolbars() { - Toolbar.init(UI); - Toolbar.setupButtonsFromConfig(); - BottomToolbar.init(); -} - -function streamHandler(stream, isMuted) { - switch (stream.type) - { - case "audio": - VideoLayout.changeLocalAudio(stream, isMuted); - break; - case "video": - VideoLayout.changeLocalVideo(stream, isMuted); - break; - case "stream": - VideoLayout.changeLocalStream(stream, isMuted); - break; - } -} - -function onXmppConnectionFailed(stropheErrorMsg) { - - var title = APP.translation.generateTranslationHTML( - "dialog.error"); - - var message; - if (stropheErrorMsg) { - message = APP.translation.generateTranslationHTML( - "dialog.connectErrorWithMsg", {msg: stropheErrorMsg}); - } else { - message = APP.translation.generateTranslationHTML( - "dialog.connectError"); - } - - messageHandler.openDialog( - title, message, true, {}, function (e, v, m, f) { return false; }); -} - -function onDisposeConference(unload) { - Toolbar.showAuthenticateButton(false); -} - -function onDisplayNameChanged(jid, displayName) { - ContactList.onDisplayNameChange(jid, displayName); - SettingsMenu.onDisplayNameChange(jid, displayName); - VideoLayout.onDisplayNameChanged(jid, displayName); -} - -function registerListeners() { - APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED); - - APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED); - APP.RTC.addStreamListener(function (stream) { - VideoLayout.onRemoteStreamAdded(stream); - }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED); - APP.RTC.addStreamListener(function (jid) { - VideoLayout.onVideoTypeChanged(jid); - }, StreamEventTypes.EVENT_TYPE_REMOTE_CHANGED); - APP.RTC.addListener(RTCEvents.LASTN_CHANGED, onLastNChanged); - APP.RTC.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (resourceJid) { - VideoLayout.onDominantSpeakerChanged(resourceJid); - }); - APP.RTC.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED, - function (lastNEndpoints, endpointsEnteringLastN, stream) { - VideoLayout.onLastNEndpointsChanged(lastNEndpoints, - endpointsEnteringLastN, stream); - }); - APP.RTC.addListener(RTCEvents.AVAILABLE_DEVICES_CHANGED, - function (devices) { - VideoLayout.setDeviceAvailabilityIcons(null, devices); - }); - APP.RTC.addListener(RTCEvents.VIDEO_MUTE, UI.setVideoMuteButtonsState); - APP.RTC.addListener(RTCEvents.DATA_CHANNEL_OPEN, function() { - // when the data channel becomes available, tell the bridge about video - // selections so that it can do adaptive simulcast, - // we want the notification to trigger even if userJid is undefined, - // or null. - var userJid = APP.UI.getLargeVideoJid(); - eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, userJid); - }); - APP.statistics.addAudioLevelListener(function(jid, audioLevel) - { - var resourceJid; - if(jid === APP.statistics.LOCAL_JID) - { - resourceJid = AudioLevels.LOCAL_LEVEL; - if(APP.RTC.localAudio.isMuted()) - { - audioLevel = 0; - } - } - else - { - resourceJid = Strophe.getResourceFromJid(jid); - } - - AudioLevels.updateAudioLevel(resourceJid, audioLevel, - UI.getLargeVideoJid()); - }); - APP.desktopsharing.addListener(function () { - ToolbarToggler.showDesktopSharingButton(); - }, DesktopSharingEventTypes.INIT); - APP.desktopsharing.addListener( - Toolbar.changeDesktopSharingButtonState, - DesktopSharingEventTypes.SWITCHING_DONE); - APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED, - VideoLayout.updateLocalConnectionStats); - APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED, - VideoLayout.updateConnectionStats); - APP.connectionquality.addListener(CQEvents.STOP, - VideoLayout.onStatsStop); - APP.xmpp.addListener(XMPPEvents.CONNECTION_FAILED, onXmppConnectionFailed); - APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference); - APP.xmpp.addListener(XMPPEvents.GRACEFUL_SHUTDOWN, function () { - messageHandler.openMessageDialog( - 'dialog.serviceUnavailable', - 'dialog.gracefulShutdown' - ); - }); - APP.xmpp.addListener(XMPPEvents.RESERVATION_ERROR, function (code, msg) { - var title = APP.translation.generateTranslationHTML( - "dialog.reservationError"); - var message = APP.translation.generateTranslationHTML( - "dialog.reservationErrorMsg", {code: code, msg: msg}); - messageHandler.openDialog( - title, - message, - true, {}, - function (event, value, message, formVals) - { - return false; - } - ); - }); - APP.xmpp.addListener(XMPPEvents.KICKED, function () { - messageHandler.openMessageDialog("dialog.sessTerminated", - "dialog.kickMessage"); - }); - APP.xmpp.addListener(XMPPEvents.MUC_DESTROYED, function (reason) { - //FIXME: use Session Terminated from translation, but - // 'reason' text comes from XMPP packet and is not translated - var title = APP.translation.generateTranslationHTML("dialog.sessTerminated"); - messageHandler.openDialog( - title, reason, true, {}, - function (event, value, message, formVals) - { - return false; - } - ); - }); - APP.xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () { - messageHandler.showError("dialog.error", - "dialog.bridgeUnavailable"); - }); - APP.xmpp.addListener(XMPPEvents.USER_ID_CHANGED, function (from, id) { - Avatar.setUserAvatar(from, id); - }); - APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged); - APP.xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined); - APP.xmpp.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, onLocalRoleChanged); - APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, onMucMemberJoined); - APP.xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged); - APP.xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus); - APP.xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject); - APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation); - APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, onMucMemberLeft); - APP.xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordRequired); - APP.xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError); - APP.xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad); - APP.xmpp.addListener(XMPPEvents.AUTHENTICATION_REQUIRED, - onAuthenticationRequired); - APP.xmpp.addListener(XMPPEvents.DEVICE_AVAILABLE, - function (resource, devices) { - VideoLayout.setDeviceAvailabilityIcons(resource, devices); - }); - - APP.xmpp.addListener(XMPPEvents.AUDIO_MUTED, VideoLayout.onAudioMute); - APP.xmpp.addListener(XMPPEvents.VIDEO_MUTED, VideoLayout.onVideoMute); - APP.xmpp.addListener(XMPPEvents.AUDIO_MUTED_BY_FOCUS, function(doMuteAudio) { - UI.setAudioMuted(doMuteAudio); - }); - APP.members.addListener(MemberEvents.DTMF_SUPPORT_CHANGED, - onDtmfSupportChanged); - APP.xmpp.addListener(XMPPEvents.START_MUTED_SETTING_CHANGED, function (audio, video) { - SettingsMenu.setStartMuted(audio, video); - }); - APP.xmpp.addListener(XMPPEvents.START_MUTED_FROM_FOCUS, function (audio, video) { - UI.setInitialMuteFromFocus(audio, video); - }); - - APP.xmpp.addListener(XMPPEvents.JINGLE_FATAL_ERROR, function (session, error) { - UI.messageHandler.showError("dialog.sorry", - "dialog.internalError"); - }); - - APP.xmpp.addListener(XMPPEvents.SET_LOCAL_DESCRIPTION_ERROR, function() { - messageHandler.showError("dialog.error", - "dialog.SLDFailure"); - }); - APP.xmpp.addListener(XMPPEvents.SET_REMOTE_DESCRIPTION_ERROR, function() { - messageHandler.showError("dialog.error", - "dialog.SRDFailure"); - }); - APP.xmpp.addListener(XMPPEvents.CREATE_ANSWER_ERROR, function() { - messageHandler.showError(); - }); - APP.xmpp.addListener(XMPPEvents.PROMPT_FOR_LOGIN, function() { - // FIXME: re-use LoginDialog which supports retries - UI.showLoginPopup(connect); - }); - - APP.xmpp.addListener(XMPPEvents.FOCUS_DISCONNECTED, function(focusComponent, retrySec) { - UI.messageHandler.notify( - null, "notify.focus", - 'disconnected', "notify.focusFail", - {component: focusComponent, ms: retrySec}); - }); - - APP.xmpp.addListener(XMPPEvents.ROOM_JOIN_ERROR, function(pres) { - UI.messageHandler.openReportDialog(null, - "dialog.joinError", pres); - }); - APP.xmpp.addListener(XMPPEvents.ROOM_CONNECT_ERROR, function(pres) { - UI.messageHandler.openReportDialog(null, - "dialog.connectError", pres); - }); - - APP.xmpp.addListener(XMPPEvents.READY_TO_JOIN, function() { - var roomName = UI.generateRoomName(); - APP.xmpp.allocateConferenceFocus(roomName, UI.checkForNicknameAndJoin); - }); - - //NicknameHandler emits this event - UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) { - APP.xmpp.addToPresence("displayName", nickname); - }); - - UI.addListener(UIEvents.LARGEVIDEO_INIT, function () { - AudioLevels.init(); - }); -} - - -/** - * Mutes/unmutes the local video. - * - * @param mute true to mute the local video; otherwise, false - * @param options an object which specifies optional arguments such as the - * boolean key byUser with default value true which - * specifies whether the method was initiated in response to a user command (in - * contrast to an automatic decision taken by the application logic) - */ -function setVideoMute(mute, options) { - APP.RTC.setVideoMute(mute, - UI.setVideoMuteButtonsState, - options); -} - -function onResize() -{ - Chat.resizeChat(); - VideoLayout.resizeLargeVideoContainer(); -} - -function bindEvents() -{ - /** - * Resizes and repositions videos in full screen mode. - */ - $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', - onResize); - - $(window).resize(onResize); -} - -UI.start = function (init) { - document.title = interfaceConfig.APP_NAME; - if(config.enableWelcomePage && window.location.pathname == "/" && - (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false")) - { - $("#videoconference_page").hide(); - var setupWelcomePage = require("./welcome_page/WelcomePage"); - setupWelcomePage(); - - return; - } - - - $("#welcome_page").hide(); - - $("#videospace").mousemove(function () { - return ToolbarToggler.showToolbar(); - }); - // Set the defaults for prompt dialogs. - jQuery.prompt.setDefaults({persistent: false}); - - - registerListeners(); - - VideoLayout.init(eventEmitter); - NicknameHandler.init(eventEmitter); - - bindEvents(); - setupPrezi(); - setupToolbars(); - setupChat(); - - - document.title = interfaceConfig.APP_NAME; - - $("#downloadlog").click(function (event) { - dump(event.target); - }); - - if(config.enableWelcomePage && window.location.pathname == "/" && - (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false")) - { - $("#videoconference_page").hide(); - var setupWelcomePage = require("./welcome_page/WelcomePage"); - setupWelcomePage(); - - return; - } - - $("#welcome_page").hide(); - - // Display notice message at the top of the toolbar - if (config.noticeMessage) { - $('#noticeText').text(config.noticeMessage); - $('#notice').css({display: 'block'}); - } - - if(config.requireDisplayName) { - var currentSettings = Settings.getSettings(); - if (!currentSettings.displayName) { - promptDisplayName(); - } - } - - init(); - - toastr.options = { - "closeButton": true, - "debug": false, - "positionClass": "notification-bottom-right", - "onclick": null, - "showDuration": "300", - "hideDuration": "1000", - "timeOut": "2000", - "extendedTimeOut": "1000", - "showEasing": "swing", - "hideEasing": "linear", - "showMethod": "fadeIn", - "hideMethod": "fadeOut", - "reposition": function() { - if(PanelToggler.isVisible()) { - $("#toast-container").addClass("notification-bottom-right-center"); - } else { - $("#toast-container").removeClass("notification-bottom-right-center"); - } - }, - "newestOnTop": false - }; - - SettingsMenu.init(); - -}; - -function chatAddError(errorMessage, originalText) -{ - return Chat.chatAddError(errorMessage, originalText); -}; - -function chatSetSubject(text) -{ - return Chat.chatSetSubject(text); -}; - -function updateChatConversation(from, displayName, message, myjid, stamp) { - return Chat.updateChatConversation(from, displayName, message, myjid, stamp); -} - -function onMucJoined(jid, info) { - Toolbar.updateRoomUrl(window.location.href); - var meHTML = APP.translation.generateTranslationHTML("me"); - $("#localNick").html(Strophe.getResourceFromJid(jid) + " (" + meHTML + ")"); - - var settings = Settings.getSettings(); - - // Make sure we configure our avatar id, before creating avatar for us - Avatar.setUserAvatar(jid, settings.email || settings.uid); - - // Add myself to the contact list. - ContactList.addContact(jid); - - // Once we've joined the muc show the toolbar - ToolbarToggler.showToolbar(); - - var displayName = !config.displayJids - ? info.displayName : Strophe.getResourceFromJid(jid); - - if (displayName) - onDisplayNameChanged('localVideoContainer', displayName); - - - VideoLayout.mucJoined(); -} - -function initEtherpad(name) { - Etherpad.init(name); -} - -function onMucMemberLeft(jid) { - console.log('left.muc', jid); - var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) + - '>.displayname').html(); - messageHandler.notify(displayName,'notify.somebody', - 'disconnected', - 'notify.disconnected'); - if(!config.startAudioMuted || - config.startAudioMuted > APP.members.size()) - UIUtil.playSoundNotification('userLeft'); - - ContactList.removeContact(jid); - - VideoLayout.participantLeft(jid); -}; - - -function onLocalRoleChanged(jid, info, pres, isModerator) -{ - - console.info("My role changed, new role: " + info.role); - onModeratorStatusChanged(isModerator); - VideoLayout.showModeratorIndicator(); - SettingsMenu.onRoleChanged(); - - if (isModerator) { - Authentication.closeAuthenticationWindow(); - messageHandler.notify(null, "notify.me", - 'connected', "notify.moderator"); - } -} - -function onModeratorStatusChanged(isModerator) { - - Toolbar.showSipCallButton(isModerator); - Toolbar.showRecordingButton( - isModerator); //&& - // FIXME: - // Recording visible if - // there are at least 2(+ 1 focus) participants - //Object.keys(connection.emuc.members).length >= 3); -} - -function onPasswordRequired(callback) { - // password is required - Toolbar.lockLockButton(); - var message = '

'; - message += APP.translation.translateString( - "dialog.passwordRequired"); - message += '

' + - ''; - - messageHandler.openTwoButtonDialog(null, null, null, message, - true, - "dialog.Ok", - function (e, v, m, f) {}, - null, - function (e, v, m, f) { - if (v) { - var lockKey = f.lockKey; - if (lockKey) { - Toolbar.setSharedKey(lockKey); - callback(lockKey); - } - } - }, - ':input:first' - ); -} - -/** - * The dialpad button is shown iff there is at least one member that supports - * DTMF (e.g. jigasi). - */ -function onDtmfSupportChanged(dtmfSupport) { - //TODO: enable when the UI is ready - //Toolbar.showDialPadButton(dtmfSupport); -} - -function onMucMemberJoined(jid, id, displayName) { - messageHandler.notify(displayName,'notify.somebody', - 'connected', - 'notify.connected'); - - if(!config.startAudioMuted || - config.startAudioMuted > APP.members.size()) - UIUtil.playSoundNotification('userJoined'); - - // Configure avatar - Avatar.setUserAvatar(jid, id); - - // Add Peer's container - VideoLayout.ensurePeerContainerExists(jid); -} - -function onMucPresenceStatus(jid, info) { - VideoLayout.setPresenceStatus(Strophe.getResourceFromJid(jid), info.status); -} - -function onMucRoleChanged(role, displayName) { - VideoLayout.showModeratorIndicator(); - - if (role === 'moderator') { - var messageKey, messageOptions = {}; - if (!displayName) { - messageKey = "notify.grantedToUnknown"; - } - else - { - messageKey = "notify.grantedTo"; - messageOptions = {to: displayName}; - } - messageHandler.notify( - displayName,'notify.somebody', - 'connected', messageKey, - messageOptions); - } -} - -function onAuthenticationRequired(intervalCallback) { - Authentication.openAuthenticationDialog( - roomName, intervalCallback, function () { - Toolbar.authenticateClicked(); - }); -}; - - -function onLastNChanged(oldValue, newValue) { - if (config.muteLocalVideoIfNotInLastN) { - setVideoMute(!newValue, { 'byUser': false }); - } -} - - -UI.toggleSmileys = function () { - Chat.toggleSmileys(); -}; - -UI.getSettings = function () { - return Settings.getSettings(); -}; - -UI.toggleFilmStrip = function () { - return BottomToolbar.toggleFilmStrip(); -}; - -UI.toggleChat = function () { - return BottomToolbar.toggleChat(); -}; - -UI.toggleContactList = function () { - return BottomToolbar.toggleContactList(); -}; - -UI.inputDisplayNameHandler = function (value) { - VideoLayout.inputDisplayNameHandler(value); -}; - - -UI.getLargeVideoJid = function() -{ - return VideoLayout.getLargeVideoJid(); -}; - -UI.generateRoomName = function() { - if(roomName) - return roomName; - var roomnode = null; - var path = window.location.pathname; - - // determinde the room node from the url - // TODO: just the roomnode or the whole bare jid? - if (config.getroomnode && typeof config.getroomnode === 'function') { - // custom function might be responsible for doing the pushstate - roomnode = config.getroomnode(path); - } else { - /* fall back to default strategy - * this is making assumptions about how the URL->room mapping happens. - * It currently assumes deployment at root, with a rewrite like the - * following one (for nginx): - location ~ ^/([a-zA-Z0-9]+)$ { - rewrite ^/(.*)$ / break; - } - */ - if (path.length > 1) { - roomnode = path.substr(1).toLowerCase(); - } else { - var word = RoomNameGenerator.generateRoomWithoutSeparator(); - roomnode = word.toLowerCase(); - - window.history.pushState('VideoChat', - 'Room: ' + word, window.location.pathname + word); - } - } - - roomName = roomnode + '@' + config.hosts.muc; - return roomName; -}; - - -UI.connectionIndicatorShowMore = function(jid) -{ - return VideoLayout.showMore(jid); -}; - -UI.showLoginPopup = function(callback) -{ - console.log('password is required'); - var message = '

'; - message += APP.translation.translateString( - "dialog.passwordRequired"); - message += '

' + - '' + - ''; - UI.messageHandler.openTwoButtonDialog(null, null, null, message, - true, - "dialog.Ok", - function (e, v, m, f) { - if (v) { - if (f.username !== null && f.password != null) { - callback(f.username, f.password); - } - } - }, - null, null, ':input:first' - - ); -} - -UI.checkForNicknameAndJoin = function () { - - Authentication.closeAuthenticationDialog(); - Authentication.stopInterval(); - - var nick = null; - if (config.useNicks) { - nick = window.prompt('Your nickname (optional)'); - } - APP.xmpp.joinRoom(roomName, config.useNicks, nick); -}; - - -function dump(elem, filename) { - elem = elem.parentNode; - elem.download = filename || 'meetlog.json'; - elem.href = 'data:application/json;charset=utf-8,\n'; - var data = APP.xmpp.populateData(); - var metadata = {}; - metadata.time = new Date(); - metadata.url = window.location.href; - metadata.ua = navigator.userAgent; - var log = APP.xmpp.getLogger(); - if (log) { - metadata.xmpp = log; - } - data.metadata = metadata; - elem.href += encodeURIComponent(JSON.stringify(data, null, ' ')); - return false; -} - -UI.getRoomName = function () { - return roomName; -}; - -UI.setInitialMuteFromFocus = function (muteAudio, muteVideo) { - if(muteAudio || muteVideo) notifyForInitialMute(); - if(muteAudio) UI.setAudioMuted(true); - if(muteVideo) UI.setVideoMute(true); -} - -/** - * Mutes/unmutes the local video. - */ -UI.toggleVideo = function () { - setVideoMute(!APP.RTC.localVideo.isMuted()); -}; - -/** - * Mutes / unmutes audio for the local participant. - */ -UI.toggleAudio = function() { - UI.setAudioMuted(!APP.RTC.localAudio.isMuted()); -}; - -/** - * Sets muted audio state for the local participant. - */ -UI.setAudioMuted = function (mute, earlyMute) { - var audioMute = null; - if(earlyMute) - audioMute = function (mute, cb) { - return APP.xmpp.sendAudioInfoPresence(mute, cb); - }; - else - audioMute = function (mute, cb) { - return APP.xmpp.setAudioMute(mute, cb); - } - if(!audioMute(mute, function () { - VideoLayout.showLocalAudioIndicator(mute); - - UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled"); - })) - { - // We still click the button. - UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled"); - return; - } - -} - -UI.addListener = function (type, listener) { - eventEmitter.on(type, listener); -} - -UI.clickOnVideo = function (videoNumber) { - var remoteVideos = $(".videocontainer:not(#mixedstream)"); - if (remoteVideos.length > videoNumber) { - remoteVideos[videoNumber].click(); - } -} - -//Used by torture -UI.showToolbar = function () { - return ToolbarToggler.showToolbar(); -} - -//Used by torture -UI.dockToolbar = function (isDock) { - return ToolbarToggler.dockToolbar(isDock); -} - -UI.setVideoMuteButtonsState = function (mute) { - var video = $('#video'); - var communicativeClass = "icon-camera"; - var muteClass = "icon-camera icon-camera-disabled"; - - if (mute) { - video.removeClass(communicativeClass); - video.addClass(muteClass); - } else { - video.removeClass(muteClass); - video.addClass(communicativeClass); - } -} - -UI.userAvatarChanged = function (resourceJid, thumbUrl, contactListUrl) { - VideoLayout.userAvatarChanged(resourceJid, thumbUrl); - ContactList.userAvatarChanged(resourceJid, contactListUrl); - if(resourceJid === APP.xmpp.myResource()) - SettingsMenu.changeAvatar(thumbUrl); -} - -UI.setVideoMute = setVideoMute; - -module.exports = UI; - - -},{"../../service/RTC/RTCEvents":101,"../../service/RTC/StreamEventTypes":103,"../../service/UI/UIEvents":104,"../../service/connectionquality/CQEvents":106,"../../service/desktopsharing/DesktopSharingEventTypes":107,"../../service/members/Events":108,"../../service/xmpp/XMPPEvents":110,"../RTC/RTCBrowserType":10,"./../settings/Settings":49,"./audio_levels/AudioLevels.js":14,"./authentication/Authentication":16,"./avatar/Avatar":18,"./etherpad/Etherpad.js":19,"./prezi/Prezi.js":20,"./side_pannels/SidePanelToggler":22,"./side_pannels/chat/Chat.js":23,"./side_pannels/contactlist/ContactList":27,"./side_pannels/settings/SettingsMenu":28,"./toolbars/BottomToolbar":29,"./toolbars/Toolbar":30,"./toolbars/ToolbarToggler":31,"./util/MessageHandler":33,"./util/NicknameHandler":34,"./util/UIUtil":35,"./videolayout/VideoLayout.js":41,"./welcome_page/RoomnameGenerator":42,"./welcome_page/WelcomePage":43,"events":1}],14:[function(require,module,exports){ -var CanvasUtil = require("./CanvasUtils"); - -var ASDrawContext = null; - -function initActiveSpeakerAudioLevels() { - var ASRadius = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2; - var ASCenter = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + ASRadius) / 2; - -// Draw a circle. - ASDrawContext.arc(ASCenter, ASCenter, ASRadius, 0, 2 * Math.PI); - -// Add a shadow around the circle - ASDrawContext.shadowColor = interfaceConfig.SHADOW_COLOR; - ASDrawContext.shadowOffsetX = 0; - ASDrawContext.shadowOffsetY = 0; -} - -/** - * The audio Levels plugin. - */ -var AudioLevels = (function(my) { - var audioLevelCanvasCache = {}; - - my.LOCAL_LEVEL = 'local'; - - my.init = function () { - ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d'); - initActiveSpeakerAudioLevels(); - } - - /** - * Updates the audio level canvas for the given peerJid. If the canvas - * didn't exist we create it. - */ - my.updateAudioLevelCanvas = function (peerJid, VideoLayout) { - var resourceJid = null; - var videoSpanId = null; - if (!peerJid) - videoSpanId = 'localVideoContainer'; - else { - resourceJid = Strophe.getResourceFromJid(peerJid); - - videoSpanId = 'participant_' + resourceJid; - } - - var videoSpan = document.getElementById(videoSpanId); - - if (!videoSpan) { - if (resourceJid) - console.error("No video element for jid", resourceJid); - else - console.error("No video element for local video."); - - return; - } - - var audioLevelCanvas = $('#' + videoSpanId + '>canvas'); - - var videoSpaceWidth = $('#remoteVideos').width(); - var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth); - var thumbnailWidth = thumbnailSize[0]; - var thumbnailHeight = thumbnailSize[1]; - - if (!audioLevelCanvas || audioLevelCanvas.length === 0) { - - audioLevelCanvas = document.createElement('canvas'); - audioLevelCanvas.className = "audiolevel"; - audioLevelCanvas.style.bottom = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px"; - audioLevelCanvas.style.left = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px"; - resizeAudioLevelCanvas( audioLevelCanvas, - thumbnailWidth, - thumbnailHeight); - - videoSpan.appendChild(audioLevelCanvas); - } else { - audioLevelCanvas = audioLevelCanvas.get(0); - - resizeAudioLevelCanvas( audioLevelCanvas, - thumbnailWidth, - thumbnailHeight); - } - }; - - /** - * Updates the audio level UI for the given resourceJid. - * - * @param resourceJid the resource jid indicating the video element for - * which we draw the audio level - * @param audioLevel the newAudio level to render - */ - my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) { - drawAudioLevelCanvas(resourceJid, audioLevel); - - var videoSpanId = getVideoSpanId(resourceJid); - - var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0); - - if (!audioLevelCanvas) - return; - - var drawContext = audioLevelCanvas.getContext('2d'); - - var canvasCache = audioLevelCanvasCache[resourceJid]; - - drawContext.clearRect (0, 0, - audioLevelCanvas.width, audioLevelCanvas.height); - drawContext.drawImage(canvasCache, 0, 0); - - if(resourceJid === AudioLevels.LOCAL_LEVEL) { - if(!APP.xmpp.myJid()) { - return; - } - resourceJid = APP.xmpp.myResource(); - } - - if(resourceJid === largeVideoResourceJid) { - window.requestAnimationFrame(function () { - AudioLevels.updateActiveSpeakerAudioLevel(audioLevel); - }); - } - }; - - my.updateActiveSpeakerAudioLevel = function(audioLevel) { - if($("#activeSpeaker").css("visibility") == "hidden" || ASDrawContext === null) - return; - - - ASDrawContext.clearRect(0, 0, 300, 300); - if(audioLevel == 0) - return; - - ASDrawContext.shadowBlur = getShadowLevel(audioLevel); - - - // Fill the shape. - ASDrawContext.fill(); - }; - - /** - * Resizes the given audio level canvas to match the given thumbnail size. - */ - function resizeAudioLevelCanvas(audioLevelCanvas, - thumbnailWidth, - thumbnailHeight) { - audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA; - audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA; - } - - /** - * Draws the audio level canvas into the cached canvas object. - * - * @param resourceJid the resource jid indicating the video element for - * which we draw the audio level - * @param audioLevel the newAudio level to render - */ - function drawAudioLevelCanvas(resourceJid, audioLevel) { - if (!audioLevelCanvasCache[resourceJid]) { - - var videoSpanId = getVideoSpanId(resourceJid); - - var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0); - - /* - * FIXME Testing has shown that audioLevelCanvasOrig may not exist. - * In such a case, the method CanvasUtil.cloneCanvas may throw an - * error. Since audio levels are frequently updated, the errors have - * been observed to pile into the console, strain the CPU. - */ - if (audioLevelCanvasOrig) - { - audioLevelCanvasCache[resourceJid] - = CanvasUtil.cloneCanvas(audioLevelCanvasOrig); - } - } - - var canvas = audioLevelCanvasCache[resourceJid]; - - if (!canvas) - return; - - var drawContext = canvas.getContext('2d'); - - drawContext.clearRect(0, 0, canvas.width, canvas.height); - - var shadowLevel = getShadowLevel(audioLevel); - - if (shadowLevel > 0) - // drawContext, x, y, w, h, r, shadowColor, shadowLevel - CanvasUtil.drawRoundRectGlow( drawContext, - interfaceConfig.CANVAS_EXTRA/2, interfaceConfig.CANVAS_EXTRA/2, - canvas.width - interfaceConfig.CANVAS_EXTRA, - canvas.height - interfaceConfig.CANVAS_EXTRA, - interfaceConfig.CANVAS_RADIUS, - interfaceConfig.SHADOW_COLOR, - shadowLevel); - } - - /** - * Returns the shadow/glow level for the given audio level. - * - * @param audioLevel the audio level from which we determine the shadow - * level - */ - function getShadowLevel (audioLevel) { - var shadowLevel = 0; - - if (audioLevel <= 0.3) { - shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3)); - } - else if (audioLevel <= 0.6) { - shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3)); - } - else { - shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4)); - } - return shadowLevel; - } - - /** - * Returns the video span id corresponding to the given resourceJid or local - * user. - */ - function getVideoSpanId(resourceJid) { - var videoSpanId = null; - if (resourceJid === AudioLevels.LOCAL_LEVEL - || (APP.xmpp.myResource() && resourceJid - === APP.xmpp.myResource())) - videoSpanId = 'localVideoContainer'; - else - videoSpanId = 'participant_' + resourceJid; - - return videoSpanId; - } - - /** - * Indicates that the remote video has been resized. - */ - $(document).bind('remotevideo.resized', function (event, width, height) { - var resized = false; - $('#remoteVideos>span>canvas').each(function() { - var canvas = $(this).get(0); - if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) { - canvas.width = width + interfaceConfig.CANVAS_EXTRA; - resized = true; - } - - if (canvas.heigh !== height + interfaceConfig.CANVAS_EXTRA) { - canvas.height = height + interfaceConfig.CANVAS_EXTRA; - resized = true; - } - }); - - if (resized) - Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) { - audioLevelCanvasCache[resourceJid].width - = width + interfaceConfig.CANVAS_EXTRA; - audioLevelCanvasCache[resourceJid].height - = height + interfaceConfig.CANVAS_EXTRA; - }); - }); - - return my; - -})(AudioLevels || {}); - -module.exports = AudioLevels; -},{"./CanvasUtils":15}],15:[function(require,module,exports){ -/** - * Utility class for drawing canvas shapes. - */ -var CanvasUtil = (function(my) { - - /** - * Draws a round rectangle with a glow. The glowWidth indicates the depth - * of the glow. - * - * @param drawContext the context of the canvas to draw to - * @param x the x coordinate of the round rectangle - * @param y the y coordinate of the round rectangle - * @param w the width of the round rectangle - * @param h the height of the round rectangle - * @param glowColor the color of the glow - * @param glowWidth the width of the glow - */ - my.drawRoundRectGlow - = function(drawContext, x, y, w, h, r, glowColor, glowWidth) { - - // Save the previous state of the context. - drawContext.save(); - - if (w < 2 * r) r = w / 2; - if (h < 2 * r) r = h / 2; - - // Draw a round rectangle. - drawContext.beginPath(); - drawContext.moveTo(x+r, y); - drawContext.arcTo(x+w, y, x+w, y+h, r); - drawContext.arcTo(x+w, y+h, x, y+h, r); - drawContext.arcTo(x, y+h, x, y, r); - drawContext.arcTo(x, y, x+w, y, r); - drawContext.closePath(); - - // Add a shadow around the rectangle - drawContext.shadowColor = glowColor; - drawContext.shadowBlur = glowWidth; - drawContext.shadowOffsetX = 0; - drawContext.shadowOffsetY = 0; - - // Fill the shape. - drawContext.fill(); - - drawContext.save(); - - drawContext.restore(); - -// 1) Uncomment this line to use Composite Operation, which is doing the -// same as the clip function below and is also antialiasing the round -// border, but is said to be less fast performance wise. - -// drawContext.globalCompositeOperation='destination-out'; - - drawContext.beginPath(); - drawContext.moveTo(x+r, y); - drawContext.arcTo(x+w, y, x+w, y+h, r); - drawContext.arcTo(x+w, y+h, x, y+h, r); - drawContext.arcTo(x, y+h, x, y, r); - drawContext.arcTo(x, y, x+w, y, r); - drawContext.closePath(); - -// 2) Uncomment this line to use Composite Operation, which is doing the -// same as the clip function below and is also antialiasing the round -// border, but is said to be less fast performance wise. - -// drawContext.fill(); - - // Comment these two lines if choosing to do the same with composite - // operation above 1 and 2. - drawContext.clip(); - drawContext.clearRect(0, 0, 277, 200); - - // Restore the previous context state. - drawContext.restore(); - }; - - /** - * Clones the given canvas. - * - * @return the new cloned canvas. - */ - my.cloneCanvas = function (oldCanvas) { - /* - * FIXME Testing has shown that oldCanvas may not exist. In such a case, - * the method CanvasUtil.cloneCanvas may throw an error. Since audio - * levels are frequently updated, the errors have been observed to pile - * into the console, strain the CPU. - */ - if (!oldCanvas) - return oldCanvas; - - //create a new canvas - var newCanvas = document.createElement('canvas'); - var context = newCanvas.getContext('2d'); - - //set dimensions - newCanvas.width = oldCanvas.width; - newCanvas.height = oldCanvas.height; - - //apply the old canvas to the new one - context.drawImage(oldCanvas, 0, 0); - - //return the new canvas - return newCanvas; - }; - - return my; -})(CanvasUtil || {}); - -module.exports = CanvasUtil; -},{}],16:[function(require,module,exports){ -/* global $, APP*/ - -var LoginDialog = require('./LoginDialog'); -var Moderator = require('../../xmpp/moderator'); - -/* Initial "authentication required" dialog */ -var authDialog = null; -/* Loop retry ID that wits for other user to create the room */ -var authRetryId = null; -var authenticationWindow = null; - -var Authentication = { - openAuthenticationDialog: function (roomName, intervalCallback, callback) { - // This is the loop that will wait for the room to be created by - // someone else. 'auth_required.moderator' will bring us back here. - authRetryId = window.setTimeout(intervalCallback, 5000); - // Show prompt only if it's not open - if (authDialog !== null) { - return; - } - // extract room name from 'room@muc.server.net' - var room = roomName.substr(0, roomName.indexOf('@')); - - var title - = APP.translation.generateTranslationHTML("dialog.WaitingForHost"); - var msg - = APP.translation.generateTranslationHTML( - "dialog.WaitForHostMsg", {room: room}); - - var buttonTxt - = APP.translation.generateTranslationHTML("dialog.IamHost"); - var buttons = []; - buttons.push({title: buttonTxt, value: "authNow"}); - - authDialog = APP.UI.messageHandler.openDialog( - title, - msg, - true, - buttons, - function (onSubmitEvent, submitValue) { - - // Do not close the dialog yet - onSubmitEvent.preventDefault(); - - // Open login popup - if (submitValue === 'authNow') { - callback(); - } - } - ); - }, - closeAuthenticationWindow: function () { - if (authenticationWindow) { - authenticationWindow.close(); - authenticationWindow = null; - } - }, - xmppAuthenticate: function () { - - var loginDialog = LoginDialog.show( - function (connection, state) { - if (!state) { - // User cancelled - loginDialog.close(); - return; - } else if (state == APP.xmpp.Status.CONNECTED) { - - loginDialog.close(); - - Authentication.stopInterval(); - Authentication.closeAuthenticationDialog(); - - // Close the connection as anonymous one will be used - // to create the conference. Session-id will authorize - // the request. - connection.disconnect(); - - var roomName = APP.UI.generateRoomName(); - Moderator.allocateConferenceFocus(roomName, function () { - // If it's not "on the fly" authentication now join - // the conference room - if (!APP.xmpp.getMUCJoined()) { - APP.UI.checkForNicknameAndJoin(); - } - }); - } - }, true); - }, - focusAuthenticationWindow: function () { - // If auth window exists just bring it to the front - if (authenticationWindow) { - authenticationWindow.focus(); - return; - } - }, - closeAuthenticationDialog: function () { - // Close authentication dialog if opened - if (authDialog) { - authDialog.close(); - authDialog = null; - } - }, - createAuthenticationWindow: function (callback, url) { - authenticationWindow = APP.UI.messageHandler.openCenteredPopup( - url, 910, 660, - // On closed - function () { - // Close authentication dialog if opened - Authentication.closeAuthenticationDialog(); - callback(); - authenticationWindow = null; - }); - return authenticationWindow; - }, - stopInterval: function () { - // Clear retry interval, so that we don't call 'doJoinAfterFocus' twice - if (authRetryId) { - window.clearTimeout(authRetryId); - authRetryId = null; - } - } -}; - -module.exports = Authentication; -},{"../../xmpp/moderator":60,"./LoginDialog":17}],17:[function(require,module,exports){ -/* global $, APP, config*/ - -var XMPP = require('../../xmpp/xmpp'); -var Moderator = require('../../xmpp/moderator'); - -//FIXME: use LoginDialog to add retries to XMPP.connect method used when -// anonymous domain is not enabled - -/** - * Creates new Dialog instance. - * @param callback function(Strophe.Connection, Strophe.Status) called - * when we either fail to connect or succeed(check Strophe.Status). - * @param obtainSession true if we want to send ConferenceIQ to Jicofo - * in order to create session-id after the connection is established. - * @constructor - */ -function Dialog(callback, obtainSession) { - - var self = this; - - var stop = false; - - var connection = APP.xmpp.createConnection(); - - var message = '

'; - message += APP.translation.translateString("dialog.passwordRequired"); - message += '

' + - '' + - ''; - - var okButton = APP.translation.generateTranslationHTML("dialog.Ok"); - - var cancelButton = APP.translation.generateTranslationHTML("dialog.Cancel"); - - var states = { - login: { - html: message, - buttons: [ - { title: okButton, value: true}, - { title: cancelButton, value: false} - ], - focus: ':input:first', - submit: function (e, v, m, f) { - e.preventDefault(); - if (v) { - var jid = f.username; - var password = f.password; - if (jid && password) { - stop = false; - connection.reset(); - connDialog.goToState('connecting'); - connection.connect(jid, password, stateHandler); - } - } else { - // User cancelled - stop = true; - callback(); - } - } - }, - connecting: { - title: APP.translation.translateString('dialog.connecting'), - html: '
', - buttons: [], - defaultButton: 0 - }, - finished: { - title: APP.translation.translateString('dialog.error'), - html: '
', - buttons: [ - { - title: APP.translation.translateString('dialog.retry'), - value: 'retry' - }, - { - title: APP.translation.translateString('dialog.Cancel'), - value: 'cancel' - }, - ], - defaultButton: 0, - submit: function (e, v, m, f) { - e.preventDefault(); - if (v === 'retry') - connDialog.goToState('login'); - else - callback(); - } - } - }; - - var connDialog - = APP.UI.messageHandler.openDialogWithStates(states, - { persistent: true, closeText: '' }, null); - - var stateHandler = function (status, message) { - if (stop) { - return; - } - - var translateKey = "connection." + XMPP.getStatusString(status); - var statusStr = APP.translation.translateString(translateKey); - - // Display current state - var connectionStatus = - connDialog.getState('connecting').find('#connectionStatus'); - - connectionStatus.text(statusStr); - - switch (status) { - case XMPP.Status.CONNECTED: - - stop = true; - if (!obtainSession) { - callback(connection, status); - return; - } - // Obtaining session-id status - connectionStatus.text( - APP.translation.translateString( - 'connection.FETCH_SESSION_ID')); - - // Authenticate with Jicofo and obtain session-id - var roomName = APP.UI.generateRoomName(); - - // Jicofo will return new session-id when connected - // from authenticated domain - connection.sendIQ( - Moderator.createConferenceIq(roomName), - function (result) { - - connectionStatus.text( - APP.translation.translateString( - 'connection.GOT_SESSION_ID')); - - stop = true; - - // Parse session-id - Moderator.parseSessionId(result); - - callback(connection, status); - }, - function (error) { - console.error("Auth on the fly failed", error); - - stop = true; - - var errorMsg = - APP.translation.translateString( - 'connection.GET_SESSION_ID_ERROR') + - $(error).find('>error').attr('code'); - - self.displayError(errorMsg); - - connection.disconnect(); - }); - - break; - case XMPP.Status.AUTHFAIL: - case XMPP.Status.CONNFAIL: - case XMPP.Status.DISCONNECTED: - - stop = true; - - callback(connection, status); - - var errorMessage = statusStr; - - if (message) - { - errorMessage += ': ' + message; - } - self.displayError(errorMessage); - - break; - default: - break; - } - }; - - /** - * Displays error message in 'finished' state which allows either to cancel - * or retry. - * @param message the final message to be displayed. - */ - this.displayError = function (message) { - - var finishedState = connDialog.getState('finished'); - - var errorMessageElem = finishedState.find('#errorMessage'); - errorMessageElem.text(message); - - connDialog.goToState('finished'); - }; - - /** - * Closes LoginDialog. - */ - this.close = function () { - stop = true; - connDialog.close(); - }; -} - -var LoginDialog = { - - /** - * Displays login prompt used to establish new XMPP connection. Given - * callback(Strophe.Connection, Strophe.Status) function will be - * called when we connect successfully(status === CONNECTED) or when we fail - * to do so. On connection failure program can call Dialog.close() method in - * order to cancel or do nothing to let the user retry. - * @param callback function(Strophe.Connection, Strophe.Status) - * called when we either fail to connect or succeed(check - * Strophe.Status). - * @param obtainSession true if we want to send ConferenceIQ to - * Jicofo in order to create session-id after the connection is - * established. - * @returns {Dialog} - */ - show: function (callback, obtainSession) { - return new Dialog(callback, obtainSession); - } -}; - -module.exports = LoginDialog; -},{"../../xmpp/moderator":60,"../../xmpp/xmpp":68}],18:[function(require,module,exports){ -var Settings = require("../../settings/Settings"); - -var users = {}; - -var Avatar = { - - /** - * Sets the user's avatar in the settings menu(if local user), contact list - * and thumbnail - * @param jid jid of the user - * @param id email or userID to be used as a hash - */ - setUserAvatar: function (jid, id) { - if (id) { - if (users[jid] === id) { - return; - } - users[jid] = id; - } - var thumbUrl = this.getThumbUrl(jid); - var contactListUrl = this.getContactListUrl(jid); - var resourceJid = Strophe.getResourceFromJid(jid); - - APP.UI.userAvatarChanged(resourceJid, thumbUrl, contactListUrl); - }, - /** - * Returns image URL for the avatar to be displayed on large video area - * where current active speaker is presented. - * @param jid full MUC jid of the user for whom we want to obtain avatar URL - */ - getActiveSpeakerUrl: function (jid) { - return this.getGravatarUrl(jid, 100); - }, - /** - * Returns image URL for the avatar to be displayed on small video thumbnail - * @param jid full MUC jid of the user for whom we want to obtain avatar URL - */ - getThumbUrl: function (jid) { - return this.getGravatarUrl(jid, 100); - }, - /** - * Returns the URL for the avatar to be displayed as contactlist item - * @param jid full MUC jid of the user for whom we want to obtain avatar URL - */ - getContactListUrl: function (jid) { - return this.getGravatarUrl(jid, 30); - }, - getGravatarUrl: function (jid, size) { - if (!jid) { - console.error("Get gravatar - jid is undefined"); - return null; - } - var id = users[jid]; - if (!id) { - console.warn( - "No avatar stored yet for " + jid + " - using JID as ID"); - id = jid; - } - return 'https://www.gravatar.com/avatar/' + - MD5.hexdigest(id.trim().toLowerCase()) + - "?d=wavatar&size=" + (size || "30"); - } - -}; - - -module.exports = Avatar; -},{"../../settings/Settings":49}],19:[function(require,module,exports){ -/* global $, config, - setLargeVideoVisible, Util */ - -var VideoLayout = require("../videolayout/VideoLayout"); -var Prezi = require("../prezi/Prezi"); -var UIUtil = require("../util/UIUtil"); - -var etherpadName = null; -var etherpadIFrame = null; -var domain = null; -var options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false"; - - -/** - * Resizes the etherpad. - */ -function resize() { - if ($('#etherpad>iframe').length) { - var remoteVideos = $('#remoteVideos'); - var availableHeight - = window.innerHeight - remoteVideos.outerHeight(); - var availableWidth = UIUtil.getAvailableVideoWidth(); - - $('#etherpad>iframe').width(availableWidth); - $('#etherpad>iframe').height(availableHeight); - } -} - -/** - * Creates the Etherpad button and adds it to the toolbar. - */ -function enableEtherpadButton() { - if (!$('#etherpadButton').is(":visible")) - $('#etherpadButton').css({display: 'inline-block'}); -} - -/** - * Creates the IFrame for the etherpad. - */ -function createIFrame() { - etherpadIFrame = VideoLayout.createEtherpadIframe( - domain + etherpadName + options, function() { - - document.domain = document.domain; - bubbleIframeMouseMove(etherpadIFrame); - setTimeout(function() { - // the iframes inside of the etherpad are - // not yet loaded when the etherpad iframe is loaded - var outer = etherpadIFrame. - contentDocument.getElementsByName("ace_outer")[0]; - bubbleIframeMouseMove(outer); - var inner = outer. - contentDocument.getElementsByName("ace_inner")[0]; - bubbleIframeMouseMove(inner); - }, 2000); - }); -} - -function bubbleIframeMouseMove(iframe){ - var existingOnMouseMove = iframe.contentWindow.onmousemove; - iframe.contentWindow.onmousemove = function(e){ - if(existingOnMouseMove) existingOnMouseMove(e); - var evt = document.createEvent("MouseEvents"); - var boundingClientRect = iframe.getBoundingClientRect(); - evt.initMouseEvent( - "mousemove", - true, // bubbles - false, // not cancelable - window, - e.detail, - e.screenX, - e.screenY, - e.clientX + boundingClientRect.left, - e.clientY + boundingClientRect.top, - e.ctrlKey, - e.altKey, - e.shiftKey, - e.metaKey, - e.button, - null // no related element - ); - iframe.dispatchEvent(evt); - }; -} - - -var Etherpad = { - /** - * Initializes the etherpad. - */ - init: function (name) { - - if (config.etherpad_base && !etherpadName && name) { - - domain = config.etherpad_base; - - etherpadName = name; - - enableEtherpadButton(); - - /** - * Resizes the etherpad, when the window is resized. - */ - $(window).resize(function () { - resize(); - }); - } - }, - - /** - * Opens/hides the Etherpad. - */ - toggleEtherpad: function (isPresentation) { - if (!etherpadIFrame) - createIFrame(); - - - if(VideoLayout.getLargeVideoState() === "etherpad") - { - VideoLayout.setLargeVideoState("video"); - } - else - { - VideoLayout.setLargeVideoState("etherpad"); - } - resize(); - } -}; - -module.exports = Etherpad; - -},{"../prezi/Prezi":20,"../util/UIUtil":35,"../videolayout/VideoLayout":41}],20:[function(require,module,exports){ -var ToolbarToggler = require("../toolbars/ToolbarToggler"); -var UIUtil = require("../util/UIUtil"); -var VideoLayout = require("../videolayout/VideoLayout"); -var messageHandler = require("../util/MessageHandler"); -var PreziPlayer = require("./PreziPlayer"); - -var preziPlayer = null; - - -/** - * Shows/hides a presentation. - */ -function setPresentationVisible(visible) { - - if (visible) { - VideoLayout.setLargeVideoState("prezi"); - } - else { - VideoLayout.setLargeVideoState("video"); - } -} - -var Prezi = { - - - /** - * Reloads the current presentation. - */ - reloadPresentation: function() { - var iframe = document.getElementById(preziPlayer.options.preziId); - iframe.src = iframe.src; - }, - - /** - * Returns true if the presentation is visible, false - - * otherwise. - */ - isPresentationVisible: function () { - return ($('#presentation>iframe') != null - && $('#presentation>iframe').css('opacity') == 1); - }, - - /** - * Opens the Prezi dialog, from which the user could choose a presentation - * to load. - */ - openPreziDialog: function() { - var myprezi = APP.xmpp.getPrezi(); - if (myprezi) { - messageHandler.openTwoButtonDialog("dialog.removePreziTitle", - null, - "dialog.removePreziMsg", - null, - false, - "dialog.Remove", - function(e,v,m,f) { - if(v) { - APP.xmpp.removePreziFromPresence(); - } - } - ); - } - else if (preziPlayer != null) { - messageHandler.openTwoButtonDialog("dialog.sharePreziTitle", - null, "dialog.sharePreziMsg", - null, - false, - "dialog.Ok", - function(e,v,m,f) { - $.prompt.close(); - } - ); - } - else { - var html = APP.translation.generateTranslationHTML( - "dialog.sharePreziTitle"); - var cancelButton = APP.translation.generateTranslationHTML( - "dialog.Cancel"); - var shareButton = APP.translation.generateTranslationHTML( - "dialog.Share"); - var backButton = APP.translation.generateTranslationHTML( - "dialog.Back"); - var buttons = []; - var buttons1 = []; - // Cancel button to both states - buttons.push({title: cancelButton, value: false}); - buttons1.push({title: cancelButton, value: false}); - // Share button - buttons.push({title: shareButton, value: true}); - // Back button - buttons1.push({title: backButton, value: true}); - var linkError = APP.translation.generateTranslationHTML( - "dialog.preziLinkError"); - var defaultUrl = APP.translation.translateString("defaultPreziLink", - {url: "http://prezi.com/wz7vhjycl7e6/my-prezi"}); - var openPreziState = { - state0: { - html: '

' + html + '

' + - '', - persistent: false, - buttons: buttons, - focus: ':input:first', - defaultButton: 0, - submit: function (e, v, m, f) { - e.preventDefault(); - if(v) - { - var preziUrl = f.preziUrl; - - if (preziUrl) - { - var urlValue - = encodeURI(UIUtil.escapeHtml(preziUrl)); - - if (urlValue.indexOf('http://prezi.com/') != 0 - && urlValue.indexOf('https://prezi.com/') != 0) - { - $.prompt.goToState('state1'); - return false; - } - else { - var presIdTmp = urlValue.substring( - urlValue.indexOf("prezi.com/") + 10); - if (!isAlphanumeric(presIdTmp) - || presIdTmp.indexOf('/') < 2) { - $.prompt.goToState('state1'); - return false; - } - else { - APP.xmpp.addToPresence("prezi", urlValue); - $.prompt.close(); - } - } - } - } - else - $.prompt.close(); - } - }, - state1: { - html: '

' + html + '

' + - linkError, - persistent: false, - buttons: buttons1, - focus: ':input:first', - defaultButton: 1, - submit: function (e, v, m, f) { - e.preventDefault(); - if (v === 0) - $.prompt.close(); - else - $.prompt.goToState('state0'); - } - } - }; - messageHandler.openDialogWithStates(openPreziState); - } - } - -}; - -/** - * A new presentation has been added. - * - * @param event the event indicating the add of a presentation - * @param jid the jid from which the presentation was added - * @param presUrl url of the presentation - * @param currentSlide the current slide to which we should move - */ -function presentationAdded(event, jid, presUrl, currentSlide) { - console.log("presentation added", presUrl); - - var presId = getPresentationId(presUrl); - - var elementId = 'participant_' - + Strophe.getResourceFromJid(jid) - + '_' + presId; - - VideoLayout.addPreziContainer(elementId); - - var controlsEnabled = false; - if (jid === APP.xmpp.myJid()) - controlsEnabled = true; - - setPresentationVisible(true); - VideoLayout.setLargeVideoHover( - function (event) { - if (Prezi.isPresentationVisible()) { - var reloadButtonRight = window.innerWidth - - $('#presentation>iframe').offset().left - - $('#presentation>iframe').width(); - - $('#reloadPresentation').css({ right: reloadButtonRight, - display:'inline-block'}); - } - }, - function (event) { - if (!Prezi.isPresentationVisible()) - $('#reloadPresentation').css({display:'none'}); - else { - var e = event.toElement || event.relatedTarget; - - if (e && e.id != 'reloadPresentation' && e.id != 'header') - $('#reloadPresentation').css({display:'none'}); - } - }); - - preziPlayer = new PreziPlayer( - 'presentation', - {preziId: presId, - width: getPresentationWidth(), - height: getPresentationHeihgt(), - controls: controlsEnabled, - debug: true - }); - - $('#presentation>iframe').attr('id', preziPlayer.options.preziId); - - preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) { - console.log("prezi status", event.value); - if (event.value == PreziPlayer.STATUS_CONTENT_READY) { - if (jid != APP.xmpp.myJid()) - preziPlayer.flyToStep(currentSlide); - } - }); - - preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) { - console.log("event value", event.value); - APP.xmpp.addToPresence("preziSlide", event.value); - }); - - $("#" + elementId).css( 'background-image', - 'url(../images/avatarprezi.png)'); - $("#" + elementId).click( - function () { - setPresentationVisible(true); - } - ); -}; - -/** - * A presentation has been removed. - * - * @param event the event indicating the remove of a presentation - * @param jid the jid for which the presentation was removed - * @param the url of the presentation - */ -function presentationRemoved(event, jid, presUrl) { - console.log('presentation removed', presUrl); - var presId = getPresentationId(presUrl); - setPresentationVisible(false); - $('#participant_' - + Strophe.getResourceFromJid(jid) - + '_' + presId).remove(); - $('#presentation>iframe').remove(); - if (preziPlayer != null) { - preziPlayer.destroy(); - preziPlayer = null; - } -}; - -/** - * Indicates if the given string is an alphanumeric string. - * Note that some special characters are also allowed (-, _ , /, &, ?, =, ;) for the - * purpose of checking URIs. - */ -function isAlphanumeric(unsafeText) { - var regex = /^[a-z0-9-_\/&\?=;]+$/i; - return regex.test(unsafeText); -} - -/** - * Returns the presentation id from the given url. - */ -function getPresentationId (presUrl) { - var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10); - return presIdTmp.substring(0, presIdTmp.indexOf('/')); -} - -/** - * Returns the presentation width. - */ -function getPresentationWidth() { - var availableWidth = UIUtil.getAvailableVideoWidth(); - var availableHeight = getPresentationHeihgt(); - - var aspectRatio = 16.0 / 9.0; - if (availableHeight < availableWidth / aspectRatio) { - availableWidth = Math.floor(availableHeight * aspectRatio); - } - return availableWidth; -} - -/** - * Returns the presentation height. - */ -function getPresentationHeihgt() { - var remoteVideos = $('#remoteVideos'); - return window.innerHeight - remoteVideos.outerHeight(); -} - -/** - * Resizes the presentation iframe. - */ -function resize() { - if ($('#presentation>iframe')) { - $('#presentation>iframe').width(getPresentationWidth()); - $('#presentation>iframe').height(getPresentationHeihgt()); - } -} - -/** - * Presentation has been removed. - */ -$(document).bind('presentationremoved.muc', presentationRemoved); - -/** - * Presentation has been added. - */ -$(document).bind('presentationadded.muc', presentationAdded); - -/* - * Indicates presentation slide change. - */ -$(document).bind('gotoslide.muc', function (event, jid, presUrl, current) { - if (preziPlayer && preziPlayer.getCurrentStep() != current) { - preziPlayer.flyToStep(current); - - var animationStepsArray = preziPlayer.getAnimationCountOnSteps(); - for (var i = 0; i < parseInt(animationStepsArray[current]); i++) { - preziPlayer.flyToStep(current, i); - } - } -}); - -$(window).resize(function () { - resize(); -}); - -module.exports = Prezi; - -},{"../toolbars/ToolbarToggler":31,"../util/MessageHandler":33,"../util/UIUtil":35,"../videolayout/VideoLayout":41,"./PreziPlayer":21}],21:[function(require,module,exports){ -(function() { - "use strict"; - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - window.PreziPlayer = (function() { - - PreziPlayer.API_VERSION = 1; - PreziPlayer.CURRENT_STEP = 'currentStep'; - PreziPlayer.CURRENT_ANIMATION_STEP = 'currentAnimationStep'; - PreziPlayer.CURRENT_OBJECT = 'currentObject'; - PreziPlayer.STATUS_LOADING = 'loading'; - PreziPlayer.STATUS_READY = 'ready'; - PreziPlayer.STATUS_CONTENT_READY = 'contentready'; - PreziPlayer.EVENT_CURRENT_STEP = "currentStepChange"; - PreziPlayer.EVENT_CURRENT_ANIMATION_STEP = "currentAnimationStepChange"; - PreziPlayer.EVENT_CURRENT_OBJECT = "currentObjectChange"; - PreziPlayer.EVENT_STATUS = "statusChange"; - PreziPlayer.EVENT_PLAYING = "isAutoPlayingChange"; - PreziPlayer.EVENT_IS_MOVING = "isMovingChange"; - PreziPlayer.domain = "https://prezi.com"; - PreziPlayer.path = "/player/"; - PreziPlayer.players = {}; - PreziPlayer.binded_methods = ['changesHandler']; - - PreziPlayer.createMultiplePlayers = function(optionArray){ - for(var i=0; i 0 && - obj.values.animationCountOnSteps && - obj.values.animationCountOnSteps[step] <= animation_step) { - animation_step = obj.values.animationCountOnSteps[step]; - } - // jump to animation steps by calling flyToNextStep() - function doAnimationSteps() { - if (obj.values.isMoving == true) { - setTimeout(doAnimationSteps, 100); // wait until the flight ends - return; - } - while (animation_step-- > 0) { - obj.flyToNextStep(); // do the animation steps - } - } - setTimeout(doAnimationSteps, 200); // 200ms is the internal "reporting" time - // jump to the step - return this.sendMessage({ - 'action': 'present', - 'data': ['moveToStep', step] - }); - }; - - PreziPlayer.prototype.toObject = /* toObject is DEPRECATED */ - PreziPlayer.prototype.flyToObject = function(objectId) { - return this.sendMessage({ - 'action': 'present', - 'data': ['moveToObject', objectId] - }); - }; - - PreziPlayer.prototype.play = function(defaultDelay) { - return this.sendMessage({ - 'action': 'present', - 'data': ['startAutoPlay', defaultDelay] - }); - }; - - PreziPlayer.prototype.stop = function() { - return this.sendMessage({ - 'action': 'present', - 'data': ['stopAutoPlay'] - }); - }; - - PreziPlayer.prototype.pause = function(defaultDelay) { - return this.sendMessage({ - 'action': 'present', - 'data': ['pauseAutoPlay', defaultDelay] - }); - }; - - PreziPlayer.prototype.getCurrentStep = function() { - return this.values.currentStep; - }; - - PreziPlayer.prototype.getCurrentAnimationStep = function() { - return this.values.currentAnimationStep; - }; - - PreziPlayer.prototype.getCurrentObject = function() { - return this.values.currentObject; - }; - - PreziPlayer.prototype.getStatus = function() { - return this.values.status; - }; - - PreziPlayer.prototype.isPlaying = function() { - return this.values.isAutoPlaying; - }; - - PreziPlayer.prototype.getStepCount = function() { - return this.values.stepCount; - }; - - PreziPlayer.prototype.getAnimationCountOnSteps = function() { - return this.values.animationCountOnSteps; - }; - - PreziPlayer.prototype.getTitle = function() { - return this.values.title; - }; - - PreziPlayer.prototype.setDimensions = function(dims) { - for (var parameter in dims) { - this.iframe[parameter] = dims[parameter]; - } - } - - PreziPlayer.prototype.getDimensions = function() { - return { - width: parseInt(this.iframe.width, 10), - height: parseInt(this.iframe.height, 10) - } - } - - PreziPlayer.prototype.on = function(event, callback) { - this.callbacks.push({ - event: event, - callback: callback - }); - }; - - PreziPlayer.prototype.off = function(event, callback) { - var j, item; - if (event === undefined) { - this.callbacks = []; - } - j = this.callbacks.length; - while (j--) { - item = this.callbacks[j]; - if (item && item.event === event && (callback === undefined || item.callback === callback)){ - this.callbacks.splice(j, 1); - } - } - }; - - if (window.addEventListener) { - window.addEventListener('message', PreziPlayer.messageReceived, false); - } else { - window.attachEvent('onmessage', PreziPlayer.messageReceived); - } - - return PreziPlayer; - - })(); - -})(); - -module.exports = PreziPlayer; - -},{}],22:[function(require,module,exports){ -var Chat = require("./chat/Chat"); -var ContactList = require("./contactlist/ContactList"); -var Settings = require("./../../settings/Settings"); -var SettingsMenu = require("./settings/SettingsMenu"); -var VideoLayout = require("../videolayout/VideoLayout"); -var ToolbarToggler = require("../toolbars/ToolbarToggler"); -var UIUtil = require("../util/UIUtil"); -var LargeVideo = require("../videolayout/LargeVideo"); - -/** - * Toggler for the chat, contact list, settings menu, etc.. - */ -var PanelToggler = (function(my) { - - var currentlyOpen = null; - var buttons = { - '#chatspace': '#chatBottomButton', - '#contactlist': '#contactListButton', - '#settingsmenu': '#settingsButton' - }; - - /** - * Toggles the windows in the side panel - * @param object the window that should be shown - * @param selector the selector for the element containing the panel - * @param onOpenComplete function to be called when the panel is opened - * @param onOpen function to be called if the window is going to be opened - * @param onClose function to be called if the window is going to be closed - */ - var toggle = function(object, selector, onOpenComplete, onOpen, onClose) { - UIUtil.buttonClick(buttons[selector], "active"); - - if (object.isVisible()) { - $("#toast-container").animate({ - right: '5px' - }, - { - queue: false, - duration: 500 - }); - $(selector).hide("slide", { - direction: "right", - queue: false, - duration: 500 - }); - if(typeof onClose === "function") { - onClose(); - } - - currentlyOpen = null; - } - else { - // Undock the toolbar when the chat is shown and if we're in a - // video mode. - if (LargeVideo.isLargeVideoVisible()) { - ToolbarToggler.dockToolbar(false); - } - - if(currentlyOpen) { - var current = $(currentlyOpen); - UIUtil.buttonClick(buttons[currentlyOpen], "active"); - current.css('z-index', 4); - setTimeout(function () { - current.css('display', 'none'); - current.css('z-index', 5); - }, 500); - } - - $("#toast-container").animate({ - right: (PanelToggler.getPanelSize()[0] + 5) + 'px' - }, - { - queue: false, - duration: 500 - }); - $(selector).show("slide", { - direction: "right", - queue: false, - duration: 500, - complete: onOpenComplete - }); - if(typeof onOpen === "function") { - onOpen(); - } - - currentlyOpen = selector; - } - }; - - /** - * Opens / closes the chat area. - */ - my.toggleChat = function() { - var chatCompleteFunction = Chat.isVisible() ? - function() {} : function () { - Chat.scrollChatToBottom(); - $('#chatspace').trigger('shown'); - }; - - VideoLayout.resizeVideoArea(!Chat.isVisible(), chatCompleteFunction); - - toggle(Chat, - '#chatspace', - function () { - // Request the focus in the nickname field or the chat input field. - if ($('#nickname').css('visibility') === 'visible') { - $('#nickinput').focus(); - } else { - $('#usermsg').focus(); - } - }, - null, - Chat.resizeChat, - null); - }; - - /** - * Opens / closes the contact list area. - */ - my.toggleContactList = function () { - var completeFunction = ContactList.isVisible() ? - function() {} : function () { $('#contactlist').trigger('shown');}; - VideoLayout.resizeVideoArea(!ContactList.isVisible(), completeFunction); - - toggle(ContactList, - '#contactlist', - null, - function() { - ContactList.setVisualNotification(false); - }, - null); - }; - - /** - * Opens / closes the settings menu - */ - my.toggleSettingsMenu = function() { - VideoLayout.resizeVideoArea(!SettingsMenu.isVisible(), function (){}); - toggle(SettingsMenu, - '#settingsmenu', - null, - function() { - var settings = Settings.getSettings(); - $('#setDisplayName').get(0).value = settings.displayName; - $('#setEmail').get(0).value = settings.email; - }, - null); - }; - - /** - * Returns the size of the side panel. - */ - my.getPanelSize = function () { - var availableHeight = window.innerHeight; - var availableWidth = window.innerWidth; - - var panelWidth = 200; - if (availableWidth * 0.2 < 200) { - panelWidth = availableWidth * 0.2; - } - - return [panelWidth, availableHeight]; - }; - - my.isVisible = function() { - return (Chat.isVisible() || ContactList.isVisible() || SettingsMenu.isVisible()); - }; - - return my; - -}(PanelToggler || {})); - -module.exports = PanelToggler; -},{"../toolbars/ToolbarToggler":31,"../util/UIUtil":35,"../videolayout/LargeVideo":37,"../videolayout/VideoLayout":41,"./../../settings/Settings":49,"./chat/Chat":23,"./contactlist/ContactList":27,"./settings/SettingsMenu":28}],23:[function(require,module,exports){ -/* global $, Util, nickname:true */ -var Replacement = require("./Replacement"); -var CommandsProcessor = require("./Commands"); -var ToolbarToggler = require("../../toolbars/ToolbarToggler"); -var smileys = require("./smileys.json").smileys; -var NicknameHandler = require("../../util/NicknameHandler"); -var UIUtil = require("../../util/UIUtil"); -var UIEvents = require("../../../../service/UI/UIEvents"); - -var notificationInterval = false; -var unreadMessages = 0; - - -/** - * Shows/hides a visual notification, indicating that a message has arrived. - */ -function setVisualNotification(show) { - var unreadMsgElement = document.getElementById('unreadMessages'); - var unreadMsgBottomElement - = document.getElementById('bottomUnreadMessages'); - - var glower = $('#chatButton'); - var bottomGlower = $('#chatBottomButton'); - - if (unreadMessages) { - unreadMsgElement.innerHTML = unreadMessages.toString(); - unreadMsgBottomElement.innerHTML = unreadMessages.toString(); - - ToolbarToggler.dockToolbar(true); - - var chatButtonElement - = document.getElementById('chatButton').parentNode; - var leftIndent = (UIUtil.getTextWidth(chatButtonElement) - - UIUtil.getTextWidth(unreadMsgElement)) / 2; - var topIndent = (UIUtil.getTextHeight(chatButtonElement) - - UIUtil.getTextHeight(unreadMsgElement)) / 2 - 3; - - unreadMsgElement.setAttribute( - 'style', - 'top:' + topIndent + - '; left:' + leftIndent + ';'); - - var chatBottomButtonElement - = document.getElementById('chatBottomButton').parentNode; - var bottomLeftIndent = (UIUtil.getTextWidth(chatBottomButtonElement) - - UIUtil.getTextWidth(unreadMsgBottomElement)) / 2; - var bottomTopIndent = (UIUtil.getTextHeight(chatBottomButtonElement) - - UIUtil.getTextHeight(unreadMsgBottomElement)) / 2 - 2; - - unreadMsgBottomElement.setAttribute( - 'style', - 'top:' + bottomTopIndent + - '; left:' + bottomLeftIndent + ';'); - - - if (!glower.hasClass('icon-chat-simple')) { - glower.removeClass('icon-chat'); - glower.addClass('icon-chat-simple'); - } - } - else { - unreadMsgElement.innerHTML = ''; - unreadMsgBottomElement.innerHTML = ''; - glower.removeClass('icon-chat-simple'); - glower.addClass('icon-chat'); - } - - if (show && !notificationInterval) { - notificationInterval = window.setInterval(function () { - glower.toggleClass('active'); - bottomGlower.toggleClass('active glowing'); - }, 800); - } - else if (!show && notificationInterval) { - window.clearInterval(notificationInterval); - notificationInterval = false; - glower.removeClass('active'); - bottomGlower.removeClass('glowing'); - bottomGlower.addClass('active'); - } -} - - -/** - * Returns the current time in the format it is shown to the user - * @returns {string} - */ -function getCurrentTime(stamp) { - var now = (stamp? new Date(stamp): new Date()); - var hour = now.getHours(); - var minute = now.getMinutes(); - var second = now.getSeconds(); - if(hour.toString().length === 1) { - hour = '0'+hour; - } - if(minute.toString().length === 1) { - minute = '0'+minute; - } - if(second.toString().length === 1) { - second = '0'+second; - } - return hour+':'+minute+':'+second; -} - -function toggleSmileys() -{ - var smileys = $('#smileysContainer'); - if(!smileys.is(':visible')) { - smileys.show("slide", { direction: "down", duration: 300}); - } else { - smileys.hide("slide", { direction: "down", duration: 300}); - } - $('#usermsg').focus(); -} - -function addClickFunction(smiley, number) { - smiley.onclick = function addSmileyToMessage() { - var usermsg = $('#usermsg'); - var message = usermsg.val(); - message += smileys['smiley' + number]; - usermsg.val(message); - usermsg.get(0).setSelectionRange(message.length, message.length); - toggleSmileys(); - usermsg.focus(); - }; -} - -/** - * Adds the smileys container to the chat - */ -function addSmileys() { - var smileysContainer = document.createElement('div'); - smileysContainer.id = 'smileysContainer'; - for(var i = 1; i <= 21; i++) { - var smileyContainer = document.createElement('div'); - smileyContainer.id = 'smiley' + i; - smileyContainer.className = 'smileyContainer'; - var smiley = document.createElement('img'); - smiley.src = 'images/smileys/smiley' + i + '.svg'; - smiley.className = 'smiley'; - addClickFunction(smiley, i); - smileyContainer.appendChild(smiley); - smileysContainer.appendChild(smileyContainer); - } - - $("#chatspace").append(smileysContainer); -} - -/** - * Resizes the chat conversation. - */ -function resizeChatConversation() { - var msgareaHeight = $('#usermsg').outerHeight(); - var chatspace = $('#chatspace'); - var width = chatspace.width(); - var chat = $('#chatconversation'); - var smileys = $('#smileysarea'); - - smileys.height(msgareaHeight); - $("#smileys").css('bottom', (msgareaHeight - 26) / 2); - $('#smileysContainer').css('bottom', msgareaHeight); - chat.width(width - 10); - chat.height(window.innerHeight - 15 - msgareaHeight); -} - -/** - * Chat related user interface. - */ -var Chat = (function (my) { - /** - * Initializes chat related interface. - */ - my.init = function () { - if(NicknameHandler.getNickname()) - Chat.setChatConversationMode(true); - NicknameHandler.addListener(UIEvents.NICKNAME_CHANGED, - function (nickname) { - Chat.setChatConversationMode(true); - }); - - $('#nickinput').keydown(function (event) { - if (event.keyCode === 13) { - event.preventDefault(); - var val = UIUtil.escapeHtml(this.value); - this.value = ''; - if (!NicknameHandler.getNickname()) { - NicknameHandler.setNickname(val); - - return; - } - } - }); - - $('#usermsg').keydown(function (event) { - if (event.keyCode === 13) { - event.preventDefault(); - var value = this.value; - $('#usermsg').val('').trigger('autosize.resize'); - this.focus(); - var command = new CommandsProcessor(value); - if(command.isCommand()) - { - command.processCommand(); - } - else - { - var message = UIUtil.escapeHtml(value); - APP.xmpp.sendChatMessage(message, NicknameHandler.getNickname()); - } - } - }); - - var onTextAreaResize = function () { - resizeChatConversation(); - Chat.scrollChatToBottom(); - }; - $('#usermsg').autosize({callback: onTextAreaResize}); - - $("#chatspace").bind("shown", - function () { - unreadMessages = 0; - setVisualNotification(false); - }); - - addSmileys(); - }; - - /** - * Appends the given message to the chat conversation. - */ - my.updateChatConversation = function (from, displayName, message, myjid, stamp) { - var divClassName = ''; - - if (APP.xmpp.myJid() === from) { - divClassName = "localuser"; - } - else { - divClassName = "remoteuser"; - - if (!Chat.isVisible()) { - unreadMessages++; - UIUtil.playSoundNotification('chatNotification'); - setVisualNotification(true); - } - } - - // replace links and smileys - // Strophe already escapes special symbols on sending, - // so we escape here only tags to avoid double & - var escMessage = message.replace(//g, '>').replace(/\n/g, '
'); - var escDisplayName = UIUtil.escapeHtml(displayName); - message = Replacement.processReplacements(escMessage); - - var messageContainer = - '
'+ - '' + - '
' + escDisplayName + - '
' + '
' + getCurrentTime(stamp) + - '
' + '
' + message + '
' + - '
'; - - $('#chatconversation').append(messageContainer); - $('#chatconversation').animate( - { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000); - }; - - /** - * Appends error message to the conversation - * @param errorMessage the received error message. - * @param originalText the original message. - */ - my.chatAddError = function(errorMessage, originalText) - { - errorMessage = UIUtil.escapeHtml(errorMessage); - originalText = UIUtil.escapeHtml(originalText); - - $('#chatconversation').append( - '
Error: ' + 'Your message' + - (originalText? (' \"'+ originalText + '\"') : "") + - ' was not sent.' + - (errorMessage? (' Reason: ' + errorMessage) : '') + '
'); - $('#chatconversation').animate( - { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000); - }; - - /** - * Sets the subject to the UI - * @param subject the subject - */ - my.chatSetSubject = function(subject) - { - if(subject) - subject = subject.trim(); - $('#subject').html(Replacement.linkify(UIUtil.escapeHtml(subject))); - if(subject === "") - { - $("#subject").css({display: "none"}); - } - else - { - $("#subject").css({display: "block"}); - } - }; - - - - /** - * Sets the chat conversation mode. - */ - my.setChatConversationMode = function (isConversationMode) { - if (isConversationMode) { - $('#nickname').css({visibility: 'hidden'}); - $('#chatconversation').css({visibility: 'visible'}); - $('#usermsg').css({visibility: 'visible'}); - $('#smileysarea').css({visibility: 'visible'}); - $('#usermsg').focus(); - } - }; - - /** - * Resizes the chat area. - */ - my.resizeChat = function () { - var chatSize = require("../SidePanelToggler").getPanelSize(); - - $('#chatspace').width(chatSize[0]); - $('#chatspace').height(chatSize[1]); - - resizeChatConversation(); - }; - - /** - * Indicates if the chat is currently visible. - */ - my.isVisible = function () { - return $('#chatspace').is(":visible"); - }; - /** - * Shows and hides the window with the smileys - */ - my.toggleSmileys = toggleSmileys; - - /** - * Scrolls chat to the bottom. - */ - my.scrollChatToBottom = function() { - setTimeout(function () { - $('#chatconversation').scrollTop( - $('#chatconversation')[0].scrollHeight); - }, 5); - }; - - - return my; -}(Chat || {})); -module.exports = Chat; -},{"../../../../service/UI/UIEvents":104,"../../toolbars/ToolbarToggler":31,"../../util/NicknameHandler":34,"../../util/UIUtil":35,"../SidePanelToggler":22,"./Commands":24,"./Replacement":25,"./smileys.json":26}],24:[function(require,module,exports){ -var UIUtil = require("../../util/UIUtil"); - -/** - * List with supported commands. The keys are the names of the commands and - * the value is the function that processes the message. - * @type {{String: function}} - */ -var commands = { - "topic" : processTopic -}; - -/** - * Extracts the command from the message. - * @param message the received message - * @returns {string} the command - */ -function getCommand(message) -{ - if(message) - { - for(var command in commands) - { - if(message.indexOf("/" + command) == 0) - return command; - } - } - return ""; -}; - -/** - * Processes the data for topic command. - * @param commandArguments the arguments of the topic command. - */ -function processTopic(commandArguments) -{ - var topic = UIUtil.escapeHtml(commandArguments); - APP.xmpp.setSubject(topic); -} - -/** - * Constructs new CommandProccessor instance from a message that - * handles commands received via chat messages. - * @param message the message - * @constructor - */ -function CommandsProcessor(message) -{ - - - var command = getCommand(message); - - /** - * Returns the name of the command. - * @returns {String} the command - */ - this.getCommand = function() - { - return command; - }; - - - var messageArgument = message.substr(command.length + 2); - - /** - * Returns the arguments of the command. - * @returns {string} - */ - this.getArgument = function() - { - return messageArgument; - }; -} - -/** - * Checks whether this instance is valid command or not. - * @returns {boolean} - */ -CommandsProcessor.prototype.isCommand = function() -{ - if(this.getCommand()) - return true; - return false; -}; - -/** - * Processes the command. - */ -CommandsProcessor.prototype.processCommand = function() -{ - if(!this.isCommand()) - return; - - commands[this.getCommand()](this.getArgument()); - -}; - -module.exports = CommandsProcessor; -},{"../../util/UIUtil":35}],25:[function(require,module,exports){ -var Smileys = require("./smileys.json"); -/** - * Processes links and smileys in "body" - */ -function processReplacements(body) -{ - //make links clickable - body = linkify(body); - - //add smileys - body = smilify(body); - - return body; -} - -/** - * Finds and replaces all links in the links in "body" - * with their - */ -function linkify(inputText) -{ - var replacedText, replacePattern1, replacePattern2, replacePattern3; - - //URLs starting with http://, https://, or ftp:// - replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim; - replacedText = inputText.replace(replacePattern1, '$1'); - - //URLs starting with "www." (without // before it, or it'd re-link the ones done above). - replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim; - replacedText = replacedText.replace(replacePattern2, '$1$2'); - - //Change email addresses to mailto:: links. - replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim; - replacedText = replacedText.replace(replacePattern3, '$1'); - - return replacedText; -} - -/** - * Replaces common smiley strings with images - */ -function smilify(body) -{ - if(!body) { - return body; - } - - var regexs = Smileys["regexs"]; - for(var smiley in regexs) { - if(regexs.hasOwnProperty(smiley)) { - body = body.replace(regexs[smiley], - ''); - } - } - - return body; -} - -module.exports = { - processReplacements: processReplacements, - linkify: linkify -}; - -},{"./smileys.json":26}],26:[function(require,module,exports){ -module.exports={ - "smileys": { - "smiley1": ":)", - "smiley2": ":(", - "smiley3": ":D", - "smiley4": "(y)", - "smiley5": " :P", - "smiley6": "(wave)", - "smiley7": "(blush)", - "smiley8": "(chuckle)", - "smiley9": "(shocked)", - "smiley10": ":*", - "smiley11": "(n)", - "smiley12": "(search)", - "smiley13": " <3", - "smiley14": "(oops)", - "smiley15": "(angry)", - "smiley16": "(angel)", - "smiley17": "(sick)", - "smiley18": ";(", - "smiley19": "(bomb)", - "smiley20": "(clap)", - "smiley21": " ;)" - }, - "regexs": { - "smiley2": /(:-\(\(|:-\(|:\(\(|:\(|\(sad\))/gi, - "smiley3": /(:-\)\)|:\)\)|\(lol\)|:-D|:D)/gi, - "smiley1": /(:-\)|:\))/gi, - "smiley4": /(\(y\)|\(Y\)|\(ok\))/gi, - "smiley5": /(:-P|:P|:-p|:p)/gi, - "smiley6": /(\(wave\))/gi, - "smiley7": /(\(blush\))/gi, - "smiley8": /(\(chuckle\))/gi, - "smiley9": /(:-0|\(shocked\))/gi, - "smiley10": /(:-\*|:\*|\(kiss\))/gi, - "smiley11": /(\(n\))/gi, - "smiley12": /(\(search\))/g, - "smiley13": /(<3|<3|&lt;3|\(L\)|\(l\)|\(H\)|\(h\))/gi, - "smiley14": /(\(oops\))/gi, - "smiley15": /(\(angry\))/gi, - "smiley16": /(\(angel\))/gi, - "smiley17": /(\(sick\))/gi, - "smiley18": /(;-\(\(|;\(\(|;-\(|;\(|:"\(|:"-\(|:~-\(|:~\(|\(upset\))/gi, - "smiley19": /(\(bomb\))/gi, - "smiley20": /(\(clap\))/gi, - "smiley21": /(;-\)|;\)|;-\)\)|;\)\)|;-D|;D|\(wink\))/gi - } -} - -},{}],27:[function(require,module,exports){ - -var Avatar = require('../../avatar/Avatar'); - -var numberOfContacts = 0; -var notificationInterval; - -/** - * Updates the number of participants in the contact list button and sets - * the glow - * @param delta indicates whether a new user has joined (1) or someone has - * left(-1) - */ -function updateNumberOfParticipants(delta) { - numberOfContacts += delta; - if (numberOfContacts === 1) { - // when the user is alone we don't show the number of participants - $("#numberOfParticipants").text(''); - ContactList.setVisualNotification(false); - } else if (numberOfContacts > 1) { - ContactList.setVisualNotification(!ContactList.isVisible()); - $("#numberOfParticipants").text(numberOfContacts); - } else { - console.error("Invalid number of participants: " + numberOfContacts); - } -} - -/** - * Creates the avatar element. - * - * @return the newly created avatar element - */ -function createAvatar(jid) { - var avatar = document.createElement('img'); - avatar.className = "icon-avatar avatar"; - avatar.src = Avatar.getContactListUrl(jid); - - return avatar; -} - -/** - * Creates the display name paragraph. - * - * @param displayName the display name to set - */ -function createDisplayNameParagraph(key, displayName) { - var p = document.createElement('p'); - if(displayName) - p.innerText = displayName; - else if(key) - { - p.setAttribute("data-i18n",key); - p.innerText = APP.translation.translateString(key); - } - - return p; -} - - -function stopGlowing(glower) { - window.clearInterval(notificationInterval); - notificationInterval = false; - glower.removeClass('glowing'); - if (!ContactList.isVisible()) { - glower.removeClass('active'); - } -} - - -/** - * Contact list. - */ -var ContactList = { - /** - * Indicates if the chat is currently visible. - * - * @return true if the chat is currently visible, false - - * otherwise - */ - isVisible: function () { - return $('#contactlist').is(":visible"); - }, - - /** - * Adds a contact for the given peerJid if such doesn't yet exist. - * - * @param peerJid the peerJid corresponding to the contact - */ - ensureAddContact: function (peerJid) { - var resourceJid = Strophe.getResourceFromJid(peerJid); - - var contact = $('#contacts>li[id="' + resourceJid + '"]'); - - if (!contact || contact.length <= 0) - ContactList.addContact(peerJid); - }, - - /** - * Adds a contact for the given peer jid. - * - * @param peerJid the jid of the contact to add - */ - addContact: function (peerJid) { - var resourceJid = Strophe.getResourceFromJid(peerJid); - - var contactlist = $('#contacts'); - - var newContact = document.createElement('li'); - newContact.id = resourceJid; - newContact.className = "clickable"; - newContact.onclick = function (event) { - if (event.currentTarget.className === "clickable") { - $(ContactList).trigger('contactclicked', [peerJid]); - } - }; - - newContact.appendChild(createAvatar(peerJid)); - newContact.appendChild(createDisplayNameParagraph("participant")); - - if (resourceJid === APP.xmpp.myResource()) { - contactlist.prepend(newContact); - } - else { - contactlist.append(newContact); - } - updateNumberOfParticipants(1); - }, - - /** - * Removes a contact for the given peer jid. - * - * @param peerJid the peerJid corresponding to the contact to remove - */ - removeContact: function (peerJid) { - var resourceJid = Strophe.getResourceFromJid(peerJid); - - var contact = $('#contacts>li[id="' + resourceJid + '"]'); - - if (contact && contact.length > 0) { - var contactlist = $('#contactlist>ul'); - - contactlist.get(0).removeChild(contact.get(0)); - - updateNumberOfParticipants(-1); - } - }, - - setVisualNotification: function (show, stopGlowingIn) { - var glower = $('#contactListButton'); - - if (show && !notificationInterval) { - notificationInterval = window.setInterval(function () { - glower.toggleClass('active glowing'); - }, 800); - } - else if (!show && notificationInterval) { - stopGlowing(glower); - } - if (stopGlowingIn) { - setTimeout(function () { - stopGlowing(glower); - }, stopGlowingIn); - } - }, - - setClickable: function (resourceJid, isClickable) { - var contact = $('#contacts>li[id="' + resourceJid + '"]'); - if (isClickable) { - contact.addClass('clickable'); - } else { - contact.removeClass('clickable'); - } - }, - - onDisplayNameChange: function (peerJid, displayName) { - if (peerJid === 'localVideoContainer') - peerJid = APP.xmpp.myJid(); - - var resourceJid = Strophe.getResourceFromJid(peerJid); - - var contactName = $('#contacts #' + resourceJid + '>p'); - - if (contactName && displayName && displayName.length > 0) - contactName.html(displayName); - }, - - userAvatarChanged: function (resourceJid, contactListUrl) { - // set the avatar in the contact list - var contact = $('#' + resourceJid + '>img'); - if (contact && contact.length > 0) { - contact.get(0).src = contactListUrl; - } - - } -}; - -module.exports = ContactList; -},{"../../avatar/Avatar":18}],28:[function(require,module,exports){ -var Avatar = require("../../avatar/Avatar"); -var Settings = require("./../../../settings/Settings"); -var UIUtil = require("../../util/UIUtil"); -var languages = require("../../../../service/translation/languages"); - -function generateLanguagesSelectBox() -{ - var currentLang = APP.translation.getCurrentLanguage(); - var html = ""; -} - - -var SettingsMenu = { - - init: function () { - $("#startMutedOptions").before(generateLanguagesSelectBox()); - APP.translation.translateElement($("#languages_selectbox")); - $('#settingsmenu>input').keyup(function(event){ - if(event.keyCode === 13) {//enter - SettingsMenu.update(); - } - }); - - if(APP.xmpp.isModerator()) - { - $("#startMutedOptions").css("display", "block"); - } - else - { - $("#startMutedOptions").css("display", "none"); - } - - $("#updateSettings").click(function () { - SettingsMenu.update(); - }); - }, - - onRoleChanged: function () { - if(APP.xmpp.isModerator()) - { - $("#startMutedOptions").css("display", "block"); - } - else - { - $("#startMutedOptions").css("display", "none"); - } - }, - - setStartMuted: function (audio, video) { - $("#startAudioMuted").attr("checked", audio); - $("#startVideoMuted").attr("checked", video); - }, - - update: function() { - var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value); - var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value); - - if(newDisplayName) { - var displayName = Settings.setDisplayName(newDisplayName); - APP.xmpp.addToPresence("displayName", displayName, true); - } - - var language = $("#languages_selectbox").val(); - APP.translation.setLanguage(language); - Settings.setLanguage(language); - - APP.xmpp.addToPresence("email", newEmail); - var email = Settings.setEmail(newEmail); - - var startAudioMuted = ($("#startAudioMuted").is(":checked")); - var startVideoMuted = ($("#startVideoMuted").is(":checked")); - APP.xmpp.addToPresence("startMuted", - [startAudioMuted, startVideoMuted]); - - Avatar.setUserAvatar(APP.xmpp.myJid(), email); - }, - - isVisible: function() { - return $('#settingsmenu').is(':visible'); - }, - - setDisplayName: function(newDisplayName) { - var displayName = Settings.setDisplayName(newDisplayName); - $('#setDisplayName').get(0).value = displayName; - }, - - onDisplayNameChange: function(peerJid, newDisplayName) { - if(peerJid === 'localVideoContainer' || - peerJid === APP.xmpp.myJid()) { - this.setDisplayName(newDisplayName); - } - }, - changeAvatar: function (thumbUrl) { - $('#avatar').get(0).src = thumbUrl; - } -}; - - -module.exports = SettingsMenu; -},{"../../../../service/translation/languages":109,"../../avatar/Avatar":18,"../../util/UIUtil":35,"./../../../settings/Settings":49}],29:[function(require,module,exports){ -var PanelToggler = require("../side_pannels/SidePanelToggler"); - -var buttonHandlers = { - "bottom_toolbar_contact_list": function () { - BottomToolbar.toggleContactList(); - }, - "bottom_toolbar_film_strip": function () { - BottomToolbar.toggleFilmStrip(); - }, - "bottom_toolbar_chat": function () { - BottomToolbar.toggleChat(); - } -}; - -var BottomToolbar = (function (my) { - my.init = function () { - for(var k in buttonHandlers) - $("#" + k).click(buttonHandlers[k]); - }; - - my.toggleChat = function() { - PanelToggler.toggleChat(); - }; - - my.toggleContactList = function() { - PanelToggler.toggleContactList(); - }; - - my.toggleFilmStrip = function() { - var filmstrip = $("#remoteVideos"); - filmstrip.toggleClass("hidden"); - }; - - $(document).bind("remotevideo.resized", function (event, width, height) { - var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18; - - $('#bottomToolbar').css({bottom: bottom + 'px'}); - }); - - return my; -}(BottomToolbar || {})); - -module.exports = BottomToolbar; - -},{"../side_pannels/SidePanelToggler":22}],30:[function(require,module,exports){ -/* global APP,$, buttonClick, config, lockRoom, - setSharedKey, Util */ -var messageHandler = require("../util/MessageHandler"); -var BottomToolbar = require("./BottomToolbar"); -var Prezi = require("../prezi/Prezi"); -var Etherpad = require("../etherpad/Etherpad"); -var PanelToggler = require("../side_pannels/SidePanelToggler"); -var Authentication = require("../authentication/Authentication"); -var UIUtil = require("../util/UIUtil"); -var AuthenticationEvents - = require("../../../service/authentication/AuthenticationEvents"); - -var roomUrl = null; -var sharedKey = ''; -var UI = null; - -var buttonHandlers = -{ - "toolbar_button_mute": function () { - return APP.UI.toggleAudio(); - }, - "toolbar_button_camera": function () { - return APP.UI.toggleVideo(); - }, - /*"toolbar_button_authentication": function () { - return Toolbar.authenticateClicked(); - },*/ - "toolbar_button_record": function () { - return toggleRecording(); - }, - "toolbar_button_security": function () { - return Toolbar.openLockDialog(); - }, - "toolbar_button_link": function () { - return Toolbar.openLinkDialog(); - }, - "toolbar_button_chat": function () { - return BottomToolbar.toggleChat(); - }, - "toolbar_button_prezi": function () { - return Prezi.openPreziDialog(); - }, - "toolbar_button_etherpad": function () { - return Etherpad.toggleEtherpad(0); - }, - "toolbar_button_desktopsharing": function () { - return APP.desktopsharing.toggleScreenSharing(); - }, - "toolbar_button_fullScreen": function() - { - UIUtil.buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen"); - return Toolbar.toggleFullScreen(); - }, - "toolbar_button_sip": function () { - return callSipButtonClicked(); - }, - "toolbar_button_dialpad": function () { - return dialpadButtonClicked(); - }, - "toolbar_button_settings": function () { - PanelToggler.toggleSettingsMenu(); - }, - "toolbar_button_hangup": function () { - return hangup(); - }, - "toolbar_button_login": function () { - Toolbar.authenticateClicked(); - }, - "toolbar_button_logout": function () { - // Ask for confirmation - messageHandler.openTwoButtonDialog( - "dialog.logoutTitle", - null, - "dialog.logoutQuestion", - null, - false, - "dialog.Yes", - function (evt, yes) { - if (yes) { - APP.xmpp.logout(function (url) { - if (url) { - window.location.href = url; - } else { - hangup(); - } - }); - } - }); - } -}; - -function hangup() { - APP.xmpp.disposeConference(); - if(config.enableWelcomePage) - { - setTimeout(function() - { - window.localStorage.welcomePageDisabled = false; - window.location.pathname = "/"; - }, 10000); - - } - - var title = APP.translation.generateTranslationHTML( - "dialog.sessTerminated"); - var msg = APP.translation.generateTranslationHTML( - "dialog.hungUp"); - var button = APP.translation.generateTranslationHTML( - "dialog.joinAgain"); - var buttons = []; - buttons.push({title: button, value: true}); - - UI.messageHandler.openDialog( - title, - msg, - true, - buttons, - function(event, value, message, formVals) - { - window.location.reload(); - return false; - } - ); -} - -/** - * Starts or stops the recording for the conference. - */ - -function toggleRecording() { - APP.xmpp.toggleRecording(function (callback) { - var msg = APP.translation.generateTranslationHTML( - "dialog.recordingToken"); - var token = APP.translation.translateString("dialog.token"); - APP.UI.messageHandler.openTwoButtonDialog(null, null, null, - '

' + msg + '

' + - '', - false, - "dialog.Save", - function (e, v, m, f) { - if (v) { - var token = f.recordingToken; - - if (token) { - callback(UIUtil.escapeHtml(token)); - } - } - }, - null, - function () { }, - ':input:first' - ); - }, Toolbar.setRecordingButtonState, Toolbar.setRecordingButtonState); -} - -/** - * Locks / unlocks the room. - */ -function lockRoom(lock) { - var currentSharedKey = ''; - if (lock) - currentSharedKey = sharedKey; - - APP.xmpp.lockRoom(currentSharedKey, function (res) { - // password is required - if (sharedKey) - { - console.log('set room password'); - Toolbar.lockLockButton(); - } - else - { - console.log('removed room password'); - Toolbar.unlockLockButton(); - } - }, function (err) { - console.warn('setting password failed', err); - messageHandler.showError("dialog.lockTitle", - "dialog.lockMessage"); - Toolbar.setSharedKey(''); - }, function () { - console.warn('room passwords not supported'); - messageHandler.showError("dialog.warning", - "dialog.passwordNotSupported"); - Toolbar.setSharedKey(''); - }); -}; - -/** - * Invite participants to conference. - */ -function inviteParticipants() { - if (roomUrl === null) - return; - - var sharedKeyText = ""; - if (sharedKey && sharedKey.length > 0) { - sharedKeyText = - APP.translation.translateString("email.sharedKey", - {sharedKey: sharedKey}); - sharedKeyText = sharedKeyText.replace(/\n/g, "%0D%0A"); - } - - var supportedBrowsers = "Chromium, Google Chrome " + - APP.translation.translateString("email.and") + " Opera"; - var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1); - var subject = APP.translation.translateString("email.subject", - {appName:interfaceConfig.APP_NAME, conferenceName: conferenceName}); - var body = APP.translation.translateString("email.body", - {appName:interfaceConfig.APP_NAME, sharedKeyText: sharedKeyText, - roomUrl: roomUrl, supportedBrowsers: supportedBrowsers}); - body = body.replace(/\n/g, "%0D%0A"); - - if (window.localStorage.displayname) { - body += "%0D%0A%0D%0A" + window.localStorage.displayname; - } - - if (interfaceConfig.INVITATION_POWERED_BY) { - body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org"; - } - - window.open("mailto:?subject=" + subject + "&body=" + body, '_blank'); -} - -function dialpadButtonClicked() -{ - //TODO show the dialpad window -} - -function callSipButtonClicked() -{ - var defaultNumber - = config.defaultSipNumber ? config.defaultSipNumber : ''; - - var sipMsg = APP.translation.generateTranslationHTML( - "dialog.sipMsg"); - messageHandler.openTwoButtonDialog(null, null, null, - '

' + sipMsg + '

' + - '', - false, - "dialog.Dial", - function (e, v, m, f) { - if (v) { - var numberInput = f.sipNumber; - if (numberInput) { - APP.xmpp.dial( - numberInput, 'fromnumber', UI.getRoomName(), sharedKey); - } - } - }, - null, null, ':input:first' - ); -} - -var Toolbar = (function (my) { - - my.init = function (ui) { - for(var k in buttonHandlers) - $("#" + k).click(buttonHandlers[k]); - UI = ui; - // Update login info - APP.xmpp.addListener( - AuthenticationEvents.IDENTITY_UPDATED, - function (authenticationEnabled, userIdentity) { - - var loggedIn = false; - if (userIdentity) { - loggedIn = true; - } - - Toolbar.showAuthenticateButton(authenticationEnabled); - - if (authenticationEnabled) { - Toolbar.setAuthenticatedIdentity(userIdentity); - - Toolbar.showLoginButton(!loggedIn); - Toolbar.showLogoutButton(loggedIn); - } - } - ); - }, - - /** - * Sets shared key - * @param sKey the shared key - */ - my.setSharedKey = function (sKey) { - sharedKey = sKey; - }; - - my.authenticateClicked = function () { - Authentication.focusAuthenticationWindow(); - if (!APP.xmpp.isExternalAuthEnabled()) { - Authentication.xmppAuthenticate(); - return; - } - // Get authentication URL - if (!APP.xmpp.getMUCJoined()) { - APP.xmpp.getLoginUrl(UI.getRoomName(), function (url) { - // If conference has not been started yet - redirect to login page - window.location.href = url; - }); - } else { - APP.xmpp.getPopupLoginUrl(UI.getRoomName(), function (url) { - // Otherwise - open popup with authentication URL - var authenticationWindow = Authentication.createAuthenticationWindow( - function () { - // On popup closed - retry room allocation - APP.xmpp.allocateConferenceFocus( - APP.UI.getRoomName(), - function () { console.info("AUTH DONE"); } - ); - }, url); - if (!authenticationWindow) { - messageHandler.openMessageDialog( - null, "dialog.popupError"); - } - }); - } - }; - - /** - * Updates the room invite url. - */ - my.updateRoomUrl = function (newRoomUrl) { - roomUrl = newRoomUrl; - - // If the invite dialog has been already opened we update the information. - var inviteLink = document.getElementById('inviteLinkRef'); - if (inviteLink) { - inviteLink.value = roomUrl; - inviteLink.select(); - $('#inviteLinkRef').parent() - .find('button[value=true]').prop('disabled', false); - } - }; - - /** - * Disables and enables some of the buttons. - */ - my.setupButtonsFromConfig = function () { - if (config.disablePrezi) - { - $("#prezi_button").css({display: "none"}); - } - }; - - /** - * Opens the lock room dialog. - */ - my.openLockDialog = function () { - // Only the focus is able to set a shared key. - if (!APP.xmpp.isModerator()) { - if (sharedKey) { - messageHandler.openMessageDialog(null, - "dialog.passwordError"); - } else { - messageHandler.openMessageDialog(null, "dialog.passwordError2"); - } - } else { - if (sharedKey) { - messageHandler.openTwoButtonDialog(null, null, - "dialog.passwordCheck", - null, - false, - "dialog.Remove", - function (e, v) { - if (v) { - Toolbar.setSharedKey(''); - lockRoom(false); - } - }); - } else { - var msg = APP.translation.generateTranslationHTML( - "dialog.passwordMsg"); - var yourPassword = APP.translation.translateString( - "dialog.yourPassword"); - messageHandler.openTwoButtonDialog(null, null, null, - '

' + msg + '

' + - '', - false, - "dialog.Save", - function (e, v, m, f) { - if (v) { - var lockKey = f.lockKey; - - if (lockKey) { - Toolbar.setSharedKey( - UIUtil.escapeHtml(lockKey)); - lockRoom(true); - } - } - }, - null, null, 'input:first' - ); - } - } - }; - - /** - * Opens the invite link dialog. - */ - my.openLinkDialog = function () { - var inviteAttreibutes; - - if (roomUrl === null) { - inviteAttreibutes = 'data-i18n="[value]roomUrlDefaultMsg" value="' + - APP.translation.translateString("roomUrlDefaultMsg") + '"'; - } else { - inviteAttreibutes = "value=\"" + encodeURI(roomUrl) + "\""; - } - messageHandler.openTwoButtonDialog("dialog.shareLink", - null, null, - '', - false, - "dialog.Invite", - function (e, v) { - if (v) { - if (roomUrl) { - inviteParticipants(); - } - } - }, - function (event) { - if (roomUrl) { - document.getElementById('inviteLinkRef').select(); - } else { - if (event && event.target) - $(event.target) - .find('button[value=true]').prop('disabled', true); - } - } - ); - }; - - /** - * Opens the settings dialog. - * FIXME: not used ? - */ - my.openSettingsDialog = function () { - var settings1 = APP.translation.generateTranslationHTML( - "dialog.settings1"); - var settings2 = APP.translation.generateTranslationHTML( - "dialog.settings2"); - var settings3 = APP.translation.generateTranslationHTML( - "dialog.settings3"); - - var yourPassword = APP.translation.translateString( - "dialog.yourPassword"); - - messageHandler.openTwoButtonDialog(null, - '

' + settings1 + '

' + - '' + - settings2 + '
' + - '' + - settings3 + - '', - null, - null, - false, - "dialog.Save", - function () { - document.getElementById('lockKey').focus(); - }, - function (e, v) { - if (v) { - if ($('#initMuted').is(":checked")) { - // it is checked - } - - if ($('#requireNicknames').is(":checked")) { - // it is checked - } - /* - var lockKey = document.getElementById('lockKey'); - - if (lockKey.value) { - setSharedKey(lockKey.value); - lockRoom(true); - } - */ - } - } - ); - }; - - /** - * Toggles the application in and out of full screen mode - * (a.k.a. presentation mode in Chrome). - */ - my.toggleFullScreen = function () { - var fsElement = document.documentElement; - - if (!document.mozFullScreen && !document.webkitIsFullScreen) { - //Enter Full Screen - if (fsElement.mozRequestFullScreen) { - fsElement.mozRequestFullScreen(); - } - else { - fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } - } else { - //Exit Full Screen - if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else { - document.webkitCancelFullScreen(); - } - } - }; - /** - * Unlocks the lock button state. - */ - my.unlockLockButton = function () { - if ($("#lockIcon").hasClass("icon-security-locked")) - UIUtil.buttonClick("#lockIcon", "icon-security icon-security-locked"); - }; - /** - * Updates the lock button state to locked. - */ - my.lockLockButton = function () { - if ($("#lockIcon").hasClass("icon-security")) - UIUtil.buttonClick("#lockIcon", "icon-security icon-security-locked"); - }; - - /** - * Shows or hides authentication button - * @param show true to show or false to hide - */ - my.showAuthenticateButton = function (show) { - if (show) { - $('#authentication').css({display: "inline"}); - } - else { - $('#authentication').css({display: "none"}); - } - }; - - // Shows or hides the 'recording' button. - my.showRecordingButton = function (show) { - if (!config.enableRecording) { - return; - } - - if (show) { - $('#recording').css({display: "inline"}); - } - else { - $('#recording').css({display: "none"}); - } - }; - - // Sets the state of the recording button - my.setRecordingButtonState = function (isRecording) { - var selector = $('#recordButton'); - if (isRecording) { - selector.removeClass("icon-recEnable"); - selector.addClass("icon-recEnable active"); - } else { - selector.removeClass("icon-recEnable active"); - selector.addClass("icon-recEnable"); - } - }; - - // Shows or hides SIP calls button - my.showSipCallButton = function (show) { - if (APP.xmpp.isSipGatewayEnabled() && show) { - $('#sipCallButton').css({display: "inline-block"}); - } else { - $('#sipCallButton').css({display: "none"}); - } - }; - - // Shows or hides the dialpad button - my.showDialPadButton = function (show) { - if (show) { - $('#dialPadButton').css({display: "inline-block"}); - } else { - $('#dialPadButton').css({display: "none"}); - } - }; - - /** - * Displays user authenticated identity name(login). - * @param authIdentity identity name to be displayed. - */ - my.setAuthenticatedIdentity = function (authIdentity) { - if (authIdentity) { - var selector = $('#toolbar_auth_identity'); - selector.css({display: "list-item"}); - selector.text(authIdentity); - } else { - $('#toolbar_auth_identity').css({display: "none"}); - } - }; - - /** - * Shows/hides login button. - * @param show true to show - */ - my.showLoginButton = function (show) { - if (show) { - $('#toolbar_button_login').css({display: "list-item"}); - } else { - $('#toolbar_button_login').css({display: "none"}); - } - }; - - /** - * Shows/hides logout button. - * @param show true to show - */ - my.showLogoutButton = function (show) { - if (show) { - $('#toolbar_button_logout').css({display: "list-item"}); - } else { - $('#toolbar_button_logout').css({display: "none"}); - } - }; - - /** - * Sets the state of the button. The button has blue glow if desktop - * streaming is active. - * @param active the state of the desktop streaming. - */ - my.changeDesktopSharingButtonState = function (active) { - var button = $("#desktopsharing > a"); - if (active) - { - button.addClass("glow"); - } - else - { - button.removeClass("glow"); - } - }; - - return my; -}(Toolbar || {})); - -module.exports = Toolbar; -},{"../../../service/authentication/AuthenticationEvents":105,"../authentication/Authentication":16,"../etherpad/Etherpad":19,"../prezi/Prezi":20,"../side_pannels/SidePanelToggler":22,"../util/MessageHandler":33,"../util/UIUtil":35,"./BottomToolbar":29}],31:[function(require,module,exports){ -/* global $, interfaceConfig, Moderator, DesktopStreaming.showDesktopSharingButton */ - -var toolbarTimeoutObject, - toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT; - -function showDesktopSharingButton() { - if (APP.desktopsharing.isDesktopSharingEnabled()) { - $('#desktopsharing').css({display: "inline"}); - } else { - $('#desktopsharing').css({display: "none"}); - } -} - -/** - * Hides the toolbar. - */ -function hideToolbar() { - if(config.alwaysVisibleToolbar) - return; - - var header = $("#header"), - bottomToolbar = $("#bottomToolbar"); - var isToolbarHover = false; - header.find('*').each(function () { - var id = $(this).attr('id'); - if ($("#" + id + ":hover").length > 0) { - isToolbarHover = true; - } - }); - if ($("#bottomToolbar:hover").length > 0) { - isToolbarHover = true; - } - - clearTimeout(toolbarTimeoutObject); - toolbarTimeoutObject = null; - - if (!isToolbarHover) { - header.hide("slide", { direction: "up", duration: 300}); - $('#subject').animate({top: "-=40"}, 300); - if ($("#remoteVideos").hasClass("hidden")) { - bottomToolbar.hide( - "slide", {direction: "right", duration: 300}); - } - } - else { - toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout); - } -} - -var ToolbarToggler = { - /** - * Shows the main toolbar. - */ - showToolbar: function () { - var header = $("#header"), - bottomToolbar = $("#bottomToolbar"); - if (!header.is(':visible') || !bottomToolbar.is(":visible")) { - header.show("slide", { direction: "up", duration: 300}); - $('#subject').animate({top: "+=40"}, 300); - if (!bottomToolbar.is(":visible")) { - bottomToolbar.show( - "slide", {direction: "right", duration: 300}); - } - - if (toolbarTimeoutObject) { - clearTimeout(toolbarTimeoutObject); - toolbarTimeoutObject = null; - } - toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout); - toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT; - } - - if (APP.xmpp.isModerator()) - { -// TODO: Enable settings functionality. -// Need to uncomment the settings button in index.html. -// $('#settingsButton').css({visibility:"visible"}); - } - - // Show/hide desktop sharing button - showDesktopSharingButton(); - }, - - - /** - * Docks/undocks the toolbar. - * - * @param isDock indicates what operation to perform - */ - dockToolbar: function (isDock) { - if (isDock) { - // First make sure the toolbar is shown. - if (!$('#header').is(':visible')) { - this.showToolbar(); - } - - // Then clear the time out, to dock the toolbar. - if (toolbarTimeoutObject) { - clearTimeout(toolbarTimeoutObject); - toolbarTimeoutObject = null; - } - } - else { - if (!$('#header').is(':visible')) { - this.showToolbar(); - } - else { - toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout); - } - } - }, - - showDesktopSharingButton: showDesktopSharingButton - -}; - -module.exports = ToolbarToggler; -},{}],32:[function(require,module,exports){ -var JitsiPopover = (function () { - /** - * Constructs new JitsiPopover and attaches it to the element - * @param element jquery selector - * @param options the options for the popover. - * @constructor - */ - function JitsiPopover(element, options) - { - this.options = { - skin: "white", - content: "" - }; - if(options) - { - if(options.skin) - this.options.skin = options.skin; - - if(options.content) - this.options.content = options.content; - } - - this.elementIsHovered = false; - this.popoverIsHovered = false; - this.popoverShown = false; - - element.data("jitsi_popover", this); - this.element = element; - this.template = '
' + - '
'; - var self = this; - this.element.on("mouseenter", function () { - self.elementIsHovered = true; - self.show(); - }).on("mouseleave", function () { - self.elementIsHovered = false; - setTimeout(function () { - self.hide(); - }, 10); - }); - } - - /** - * Shows the popover - */ - JitsiPopover.prototype.show = function () { - this.createPopover(); - this.popoverShown = true; - - }; - - /** - * Hides the popover - */ - JitsiPopover.prototype.hide = function () { - if(!this.elementIsHovered && !this.popoverIsHovered && this.popoverShown) - { - this.forceHide(); - } - }; - - /** - * Hides the popover - */ - JitsiPopover.prototype.forceHide = function () { - $(".jitsipopover").remove(); - this.popoverShown = false; - }; - - /** - * Creates the popover html - */ - JitsiPopover.prototype.createPopover = function () { - $("body").append(this.template); - $(".jitsipopover > .jitsipopover-content").html(this.options.content); - var self = this; - $(".jitsipopover").on("mouseenter", function () { - self.popoverIsHovered = true; - }).on("mouseleave", function () { - self.popoverIsHovered = false; - self.hide(); - }); - - this.refreshPosition(); - }; - - /** - * Refreshes the position of the popover - */ - JitsiPopover.prototype.refreshPosition = function () { - $(".jitsipopover").position({ - my: "bottom", - at: "top", - collision: "fit", - of: this.element, - using: function (position, elements) { - var calcLeft = elements.target.left - elements.element.left + elements.target.width/2; - $(".jitsipopover").css({top: position.top, left: position.left, display: "table"}); - $(".jitsipopover > .arrow").css({left: calcLeft}); - $(".jitsipopover > .jitsiPopupmenuPadding").css({left: calcLeft - 50}); - } - }); - }; - - /** - * Updates the content of popover. - * @param content new content - */ - JitsiPopover.prototype.updateContent = function (content) { - this.options.content = content; - if(!this.popoverShown) - return; - $(".jitsipopover").remove(); - this.createPopover(); - }; - - return JitsiPopover; - - -})(); - -module.exports = JitsiPopover; -},{}],33:[function(require,module,exports){ -/* global $, APP, jQuery, toastr */ -var messageHandler = (function(my) { - - /** - * Shows a message to the user. - * - * @param titleString the title of the message - * @param messageString the text of the message - */ - my.openMessageDialog = function(titleKey, messageKey) { - var title = null; - if(titleKey) - { - title = APP.translation.generateTranslationHTML(titleKey); - } - var message = APP.translation.generateTranslationHTML(messageKey); - $.prompt(message, - { - title: title, - persistent: false - } - ); - }; - - /** - * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel. - * - * @param titleString the title of the message - * @param msgString the text of the message - * @param persistent boolean value which determines whether the message is persistent or not - * @param leftButton the fist button's text - * @param submitFunction function to be called on submit - * @param loadedFunction function to be called after the prompt is fully loaded - * @param closeFunction function to be called after the prompt is closed - * @param focus optional focus selector or button index to be focused after - * the dialog is opened - * @param defaultButton index of default button which will be activated when - * the user press 'enter'. Indexed from 0. - */ - my.openTwoButtonDialog = function(titleKey, titleString, msgKey, msgString, - persistent, leftButtonKey, submitFunction, loadedFunction, - closeFunction, focus, defaultButton) - { - var buttons = []; - - var leftButton = APP.translation.generateTranslationHTML(leftButtonKey); - buttons.push({ title: leftButton, value: true}); - - var cancelButton - = APP.translation.generateTranslationHTML("dialog.Cancel"); - buttons.push({title: cancelButton, value: false}); - - var message = msgString, title = titleString; - if (titleKey) - { - title = APP.translation.generateTranslationHTML(titleKey); - } - if (msgKey) { - message = APP.translation.generateTranslationHTML(msgKey); - } - $.prompt(message, { - title: title, - persistent: false, - buttons: buttons, - defaultButton: defaultButton, - focus: focus, - loaded: loadedFunction, - submit: submitFunction, - close: closeFunction - }); - }; - - /** - * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel. - * - * @param titleString the title of the message - * @param msgString the text of the message - * @param persistent boolean value which determines whether the message is persistent or not - * @param buttons object with the buttons. The keys must be the name of the button and value is the value - * that will be passed to submitFunction - * @param submitFunction function to be called on submit - * @param loadedFunction function to be called after the prompt is fully loaded - */ - my.openDialog = function (titleString, msgString, persistent, buttons, - submitFunction, loadedFunction) { - var args = { - title: titleString, - persistent: persistent, - buttons: buttons, - defaultButton: 1, - loaded: loadedFunction, - submit: submitFunction - }; - if (persistent) { - args.closeText = ''; - } - return new Impromptu(msgString, args); - }; - - /** - * Closes currently opened dialog. - */ - my.closeDialog = function () { - $.prompt.close(); - }; - - /** - * Shows a dialog with different states to the user. - * - * @param statesObject object containing all the states of the dialog - */ - my.openDialogWithStates = function (statesObject, options) { - - return new Impromptu(statesObject, options); - }; - - /** - * Opens new popup window for given url centered over current - * window. - * - * @param url the URL to be displayed in the popup window - * @param w the width of the popup window - * @param h the height of the popup window - * @param onPopupClosed optional callback function called when popup window - * has been closed. - * - * @returns popup window object if opened successfully or undefined - * in case we failed to open it(popup blocked) - */ - my.openCenteredPopup = function (url, w, h, onPopupClosed) { - var l = window.screenX + (window.innerWidth / 2) - (w / 2); - var t = window.screenY + (window.innerHeight / 2) - (h / 2); - var popup = window.open( - url, '_blank', - 'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + ''); - if (popup && onPopupClosed) { - var pollTimer = window.setInterval(function () { - if (popup.closed !== false) { - window.clearInterval(pollTimer); - onPopupClosed(); - } - }, 200); - } - return popup; - }; - - /** - * Shows a dialog prompting the user to send an error report. - * - * @param titleString the title of the message - * @param msgString the text of the message - * @param error the error that is being reported - */ - my.openReportDialog = function(titleKey, msgKey, error) { - my.openMessageDialog(titleKey, msgKey); - console.log(error); - //FIXME send the error to the server - }; - - /** - * Shows an error dialog to the user. - * @param title the title of the message - * @param message the text of the messafe - */ - my.showError = function(titleKey, msgKey) { - - if(!titleKey) { - titleKey = "dialog.oops"; - } - if(!msgKey) - { - msgKey = "dialog.defaultError"; - } - messageHandler.openMessageDialog(titleKey, msgKey); - }; - - my.notify = function(displayName, displayNameKey, - cls, messageKey, messageArguments, options) { - var displayNameSpan = '" + APP.translation.translateString(displayNameKey); - } - displayNameSpan += ""; - toastr.info( - displayNameSpan + '
' + - '" + - APP.translation.translateString(messageKey, - messageArguments) + - '', null, options); - }; - - return my; -}(messageHandler || {})); - -module.exports = messageHandler; - - - -},{}],34:[function(require,module,exports){ -var UIEvents = require("../../../service/UI/UIEvents"); - -var nickname = null; -var eventEmitter = null; - -var NickanameHandler = { - init: function (emitter) { - eventEmitter = emitter; - var storedDisplayName = window.localStorage.displayname; - if (storedDisplayName) { - nickname = storedDisplayName; - } - }, - setNickname: function (newNickname) { - if (!newNickname || nickname === newNickname) - return; - - nickname = newNickname; - window.localStorage.displayname = nickname; - eventEmitter.emit(UIEvents.NICKNAME_CHANGED, newNickname); - }, - getNickname: function () { - return nickname; - }, - addListener: function (type, listener) { - eventEmitter.on(type, listener); - } -}; - -module.exports = NickanameHandler; -},{"../../../service/UI/UIEvents":104}],35:[function(require,module,exports){ -/** - * Created by hristo on 12/22/14. - */ -module.exports = { - /** - * Returns the available video width. - */ - getAvailableVideoWidth: function (isVisible) { - var PanelToggler = require("../side_pannels/SidePanelToggler"); - if(typeof isVisible === "undefined" || isVisible === null) - isVisible = PanelToggler.isVisible(); - var rightPanelWidth - = isVisible ? PanelToggler.getPanelSize()[0] : 0; - - return window.innerWidth - rightPanelWidth; - }, - /** - * Changes the style class of the element given by id. - */ - buttonClick: function(id, classname) { - $(id).toggleClass(classname); // add the class to the clicked element - }, - /** - * Returns the text width for the given element. - * - * @param el the element - */ - getTextWidth: function (el) { - return (el.clientWidth + 1); - }, - - /** - * Returns the text height for the given element. - * - * @param el the element - */ - getTextHeight: function (el) { - return (el.clientHeight + 1); - }, - - /** - * Plays the sound given by id. - * - * @param id the identifier of the audio element. - */ - playSoundNotification: function (id) { - document.getElementById(id).play(); - }, - - /** - * Escapes the given text. - */ - escapeHtml: function (unsafeText) { - return $('
').text(unsafeText).html(); - }, - - imageToGrayScale: function (canvas) { - var context = canvas.getContext('2d'); - var imgData = context.getImageData(0, 0, canvas.width, canvas.height); - var pixels = imgData.data; - - for (var i = 0, n = pixels.length; i < n; i += 4) { - var grayscale - = pixels[i] * .3 + pixels[i+1] * .59 + pixels[i+2] * .11; - pixels[i ] = grayscale; // red - pixels[i+1] = grayscale; // green - pixels[i+2] = grayscale; // blue - // pixels[i+3] is alpha - } - // redraw the image in black & white - context.putImageData(imgData, 0, 0); - }, - - setTooltip: function (element, key, position) { - element.setAttribute("data-i18n", "[data-content]" + key); - element.setAttribute("data-toggle", "popover"); - element.setAttribute("data-placement", position); - element.setAttribute("data-html", true); - element.setAttribute("data-container", "body"); - } - - -}; -},{"../side_pannels/SidePanelToggler":22}],36:[function(require,module,exports){ -var JitsiPopover = require("../util/JitsiPopover"); - -/** - * Constructs new connection indicator. - * @param videoContainer the video container associated with the indicator. - * @constructor - */ -function ConnectionIndicator(videoContainer, jid) -{ - this.videoContainer = videoContainer; - this.bandwidth = null; - this.packetLoss = null; - this.bitrate = null; - this.showMoreValue = false; - this.resolution = null; - this.transport = []; - this.popover = null; - this.jid = jid; - this.create(); -} - -/** - * Values for the connection quality - * @type {{98: string, - * 81: string, - * 64: string, - * 47: string, - * 30: string, - * 0: string}} - */ -ConnectionIndicator.connectionQualityValues = { - 98: "18px", //full - 81: "15px",//4 bars - 64: "11px",//3 bars - 47: "7px",//2 bars - 30: "3px",//1 bar - 0: "0px"//empty -}; - -ConnectionIndicator.getIP = function(value) -{ - return value.substring(0, value.lastIndexOf(":")); -}; - -ConnectionIndicator.getPort = function(value) -{ - return value.substring(value.lastIndexOf(":") + 1, value.length); -}; - -ConnectionIndicator.getStringFromArray = function (array) { - var res = ""; - for(var i = 0; i < array.length; i++) - { - res += (i === 0? "" : ", ") + array[i]; - } - return res; -}; - -/** - * Generates the html content. - * @returns {string} the html content. - */ -ConnectionIndicator.prototype.generateText = function () { - var downloadBitrate, uploadBitrate, packetLoss, resolution, i; - - var translate = APP.translation.translateString; - - if(this.bitrate === null) - { - downloadBitrate = "N/A"; - uploadBitrate = "N/A"; - } - else - { - downloadBitrate = - this.bitrate.download? this.bitrate.download + " Kbps" : "N/A"; - uploadBitrate = - this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A"; - } - - if(this.packetLoss === null) - { - packetLoss = "N/A"; - } - else - { - - packetLoss = "" + - (this.packetLoss.download !== null? this.packetLoss.download : "N/A") + - "% " + - (this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") + "%"; - } - - var resolutionValue = null; - if(this.resolution && this.jid != null) - { - var keys = Object.keys(this.resolution); - for(var ssrc in this.resolution) - { - resolutionValue = this.resolution[ssrc]; - } - } - - if(this.jid === null) - { - resolution = ""; - if(this.resolution === null || !Object.keys(this.resolution) || - Object.keys(this.resolution).length === 0) - { - resolution = "N/A"; - } - else - for(i in this.resolution) - { - resolutionValue = this.resolution[i]; - if(resolutionValue) - { - if(resolutionValue.height && - resolutionValue.width) - { - resolution += (resolution === ""? "" : ", ") + - resolutionValue.width + "x" + - resolutionValue.height; - } - } - } - } - else if(!resolutionValue || - !resolutionValue.height || - !resolutionValue.width) - { - resolution = "N/A"; - } - else - { - resolution = resolutionValue.width + "x" + resolutionValue.height; - } - - var result = "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
" + - translate("connectionindicator.bitrate") + "" + - downloadBitrate + " " + - uploadBitrate + "
" + - translate("connectionindicator.packetloss") + "" + packetLoss + "
" + - translate("connectionindicator.resolution") + "" + resolution + "
"; - - if(this.videoContainer.videoSpanId == "localVideoContainer") { - result += "
" + - translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) + - "

"; - } - - if(this.showMoreValue) - { - var downloadBandwidth, uploadBandwidth, transport; - if(this.bandwidth === null) - { - downloadBandwidth = "N/A"; - uploadBandwidth = "N/A"; - } - else - { - downloadBandwidth = this.bandwidth.download? - this.bandwidth.download + " Kbps" : - "N/A"; - uploadBandwidth = this.bandwidth.upload? - this.bandwidth.upload + " Kbps" : - "N/A"; - } - - if(!this.transport || this.transport.length === 0) - { - transport = "" + - "" + - translate("connectionindicator.address") + "" + - " N/A"; - } - else - { - var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]}; - for(i = 0; i < this.transport.length; i++) - { - var ip = ConnectionIndicator.getIP(this.transport[i].ip); - var port = ConnectionIndicator.getPort(this.transport[i].ip); - var localIP = - ConnectionIndicator.getIP(this.transport[i].localip); - var localPort = - ConnectionIndicator.getPort(this.transport[i].localip); - if(data.remoteIP.indexOf(ip) == -1) - { - data.remoteIP.push(ip); - } - - if(data.remotePort.indexOf(port) == -1) - { - data.remotePort.push(port); - } - - if(data.localIP.indexOf(localIP) == -1) - { - data.localIP.push(localIP); - } - - if(data.localPort.indexOf(localPort) == -1) - { - data.localPort.push(localPort); - } - - } - - var local_address_key = "connectionindicator.localaddress"; - var remote_address_key = "connectionindicator.remoteaddress"; - var localTransport = - "" + - translate(local_address_key, {count: data.localIP.length}) + - " " + - ConnectionIndicator.getStringFromArray(data.localIP) + - ""; - transport = - "" + - translate(remote_address_key, - {count: data.remoteIP.length}) + - " " + - ConnectionIndicator.getStringFromArray(data.remoteIP) + - ""; - - var key_remote = "connectionindicator.remoteport", - key_local = "connectionindicator.localport"; - - transport += "" + - "" + - "" + - translate(key_remote, {count: this.transport.length}) + - ""; - localTransport += "" + - "" + - "" + - translate(key_local, {count: this.transport.length}) + - ""; - - transport += - ConnectionIndicator.getStringFromArray(data.remotePort); - localTransport += - ConnectionIndicator.getStringFromArray(data.localPort); - transport += ""; - transport += localTransport + ""; - transport +="" + - "" + - translate("connectionindicator.transport") + "" + - "" + this.transport[0].type + ""; - - } - - result += "" + - "" + - ""; - - result += transport + "
" + - "" + - translate("connectionindicator.bandwidth") + "" + - "" + - "" + - downloadBandwidth + - " " + - uploadBandwidth + "
"; - - } - - return result; -}; - -/** - * Shows or hide the additional information. - */ -ConnectionIndicator.prototype.showMore = function () { - this.showMoreValue = !this.showMoreValue; - this.updatePopoverData(); -}; - - -function createIcon(classes) -{ - var icon = document.createElement("span"); - for(var i in classes) - { - icon.classList.add(classes[i]); - } - icon.appendChild( - document.createElement("i")).classList.add("icon-connection"); - return icon; -} - -/** - * Creates the indicator - */ -ConnectionIndicator.prototype.create = function () { - this.connectionIndicatorContainer = document.createElement("div"); - this.connectionIndicatorContainer.className = "connectionindicator"; - this.connectionIndicatorContainer.style.display = "none"; - this.videoContainer.container.appendChild(this.connectionIndicatorContainer); - this.popover = new JitsiPopover( - $("#" + this.videoContainer.videoSpanId + " > .connectionindicator"), - {content: "
" + - APP.translation.translateString("connectionindicator.na") + "
", - skin: "black"}); - - this.emptyIcon = this.connectionIndicatorContainer.appendChild( - createIcon(["connection", "connection_empty"])); - this.fullIcon = this.connectionIndicatorContainer.appendChild( - createIcon(["connection", "connection_full"])); - -}; - -/** - * Removes the indicator - */ -ConnectionIndicator.prototype.remove = function() -{ - if (this.connectionIndicatorContainer.parentNode) { - this.connectionIndicatorContainer.parentNode.removeChild( - this.connectionIndicatorContainer); - } - this.popover.forceHide(); - -}; - -/** - * Updates the data of the indicator - * @param percent the percent of connection quality - * @param object the statistics data. - */ -ConnectionIndicator.prototype.updateConnectionQuality = -function (percent, object) { - - if(percent === null) - { - this.connectionIndicatorContainer.style.display = "none"; - this.popover.forceHide(); - return; - } - else - { - if(this.connectionIndicatorContainer.style.display == "none") { - this.connectionIndicatorContainer.style.display = "block"; - this.videoContainer.updateIconPositions(); - } - } - this.bandwidth = object.bandwidth; - this.bitrate = object.bitrate; - this.packetLoss = object.packetLoss; - this.transport = object.transport; - if(object.resolution) - { - this.resolution = object.resolution; - } - for(var quality in ConnectionIndicator.connectionQualityValues) - { - if(percent >= quality) - { - this.fullIcon.style.width = - ConnectionIndicator.connectionQualityValues[quality]; - } - } - this.updatePopoverData(); -}; - -/** - * Updates the resolution - * @param resolution the new resolution - */ -ConnectionIndicator.prototype.updateResolution = function (resolution) { - this.resolution = resolution; - this.updatePopoverData(); -}; - -/** - * Updates the content of the popover - */ -ConnectionIndicator.prototype.updatePopoverData = function () { - this.popover.updateContent( - "
" + this.generateText() + "
"); - APP.translation.translateElement($(".connection_info")); -}; - -/** - * Hides the popover - */ -ConnectionIndicator.prototype.hide = function () { - this.popover.forceHide(); -}; - -/** - * Hides the indicator - */ -ConnectionIndicator.prototype.hideIndicator = function () { - this.connectionIndicatorContainer.style.display = "none"; - if(this.popover) - this.popover.forceHide(); -}; - -module.exports = ConnectionIndicator; -},{"../util/JitsiPopover":32}],37:[function(require,module,exports){ -var Avatar = require("../avatar/Avatar"); -var RTCBrowserType = require("../../RTC/RTCBrowserType"); -var UIUtil = require("../util/UIUtil"); -var UIEvents = require("../../../service/UI/UIEvents"); -var xmpp = require("../../xmpp/xmpp"); -var ToolbarToggler = require("../toolbars/ToolbarToggler"); - -// FIXME: With Temasys we have to re-select everytime -//var video = $('#largeVideo'); - -var currentVideoWidth = null; -var currentVideoHeight = null; -// By default we use camera -var getVideoSize = getCameraVideoSize; -var getVideoPosition = getCameraVideoPosition; -/** - * The small video instance that is displayed in the large video - * @type {SmallVideo} - */ -var currentSmallVideo = null; -/** - * Indicates whether the large video is enabled. - * @type {boolean} - */ -var isEnabled = true; -/** - * Current large video state. - * Possible values - video, prezi or etherpad. - * @type {string} - */ -var state = "video"; - -/** - * Returns the html element associated with the passed state of large video - * @param state the state. - * @returns {JQuery|*|jQuery|HTMLElement} the container. - */ -function getContainerByState(state) -{ - var selector = null; - switch (state) - { - case "video": - selector = "#largeVideo"; - break; - case "etherpad": - selector = "#etherpad>iframe"; - break; - case "prezi": - selector = "#presentation>iframe"; - break; - } - return (selector !== null)? $(selector) : null; -} - -/** - * Sets the size and position of the given video element. - * - * @param video the video element to position - * @param width the desired video width - * @param height the desired video height - * @param horizontalIndent the left and right indent - * @param verticalIndent the top and bottom indent - */ -function positionVideo(video, - width, - height, - horizontalIndent, - verticalIndent, - animate) { - if(animate) - { - video.animate({ - width: width, - height: height, - top: verticalIndent, - bottom: verticalIndent, - left: horizontalIndent, - right: horizontalIndent - }, - { - queue: false, - duration: 500 - }); - } - else - { - video.width(width); - video.height(height); - video.css({ top: verticalIndent + 'px', - bottom: verticalIndent + 'px', - left: horizontalIndent + 'px', - right: horizontalIndent + 'px'}); - } - -} - - -/** - * Returns an array of the video dimensions, so that it keeps it's aspect - * ratio and fits available area with it's larger dimension. This method - * ensures that whole video will be visible and can leave empty areas. - * - * @return an array with 2 elements, the video width and the video height - */ -function getDesktopVideoSize(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - if (!videoWidth) - videoWidth = currentVideoWidth; - if (!videoHeight) - videoHeight = currentVideoHeight; - - var aspectRatio = videoWidth / videoHeight; - - var availableWidth = Math.max(videoWidth, videoSpaceWidth); - var availableHeight = Math.max(videoHeight, videoSpaceHeight); - - videoSpaceHeight -= $('#remoteVideos').outerHeight(); - - if (availableWidth / aspectRatio >= videoSpaceHeight) - { - availableHeight = videoSpaceHeight; - availableWidth = availableHeight * aspectRatio; - } - - if (availableHeight * aspectRatio >= videoSpaceWidth) - { - availableWidth = videoSpaceWidth; - availableHeight = availableWidth / aspectRatio; - } - - return [availableWidth, availableHeight]; -} - - -/** - * Returns an array of the video horizontal and vertical indents, - * so that if fits its parent. - * - * @return an array with 2 elements, the horizontal indent and the vertical - * indent - */ -function getCameraVideoPosition(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - // Parent height isn't completely calculated when we position the video in - // full screen mode and this is why we use the screen height in this case. - // Need to think it further at some point and implement it properly. - var isFullScreen = document.fullScreen || - document.mozFullScreen || - document.webkitIsFullScreen; - if (isFullScreen) - videoSpaceHeight = window.innerHeight; - - var horizontalIndent = (videoSpaceWidth - videoWidth) / 2; - var verticalIndent = (videoSpaceHeight - videoHeight) / 2; - - return [horizontalIndent, verticalIndent]; -} - -/** - * Returns an array of the video horizontal and vertical indents. - * Centers horizontally and top aligns vertically. - * - * @return an array with 2 elements, the horizontal indent and the vertical - * indent - */ -function getDesktopVideoPosition(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - - var horizontalIndent = (videoSpaceWidth - videoWidth) / 2; - - var verticalIndent = 0;// Top aligned - - return [horizontalIndent, verticalIndent]; -} - - -/** - * Returns an array of the video dimensions, so that it covers the screen. - * It leaves no empty areas, but some parts of the video might not be visible. - * - * @return an array with 2 elements, the video width and the video height - */ -function getCameraVideoSize(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - if (!videoWidth) - videoWidth = currentVideoWidth; - if (!videoHeight) - videoHeight = currentVideoHeight; - - var aspectRatio = videoWidth / videoHeight; - - var availableWidth = Math.max(videoWidth, videoSpaceWidth); - var availableHeight = Math.max(videoHeight, videoSpaceHeight); - - if (availableWidth / aspectRatio < videoSpaceHeight) { - availableHeight = videoSpaceHeight; - availableWidth = availableHeight * aspectRatio; - } - - if (availableHeight * aspectRatio < videoSpaceWidth) { - availableWidth = videoSpaceWidth; - availableHeight = availableWidth / aspectRatio; - } - - return [availableWidth, availableHeight]; -} - -/** - * Updates the src of the active speaker avatar - * @param jid of the current active speaker - */ -function updateActiveSpeakerAvatarSrc() { - var avatar = $("#activeSpeakerAvatar")[0]; - var jid = currentSmallVideo.peerJid; - var url = Avatar.getActiveSpeakerUrl(jid); - if (avatar.src === url) - return; - if (jid) { - avatar.src = url; - currentSmallVideo.showAvatar(); - } -} - -/** - * Change the video source of the large video. - * @param isVisible - */ -function changeVideo(isVisible) { - - if (!currentSmallVideo) { - console.error("Unable to change large video - no 'currentSmallVideo'"); - return; - } - - updateActiveSpeakerAvatarSrc(); - - APP.RTC.setVideoSrc($('#largeVideo')[0], currentSmallVideo.getSrc()); - - var videoTransform = document.getElementById('largeVideo') - .style.webkitTransform; - - var flipX = currentSmallVideo.flipX; - - if (flipX && videoTransform !== 'scaleX(-1)') { - document.getElementById('largeVideo').style.webkitTransform - = "scaleX(-1)"; - } - else if (!flipX && videoTransform === 'scaleX(-1)') { - document.getElementById('largeVideo').style.webkitTransform - = "none"; - } - - var isDesktop = APP.RTC.isVideoSrcDesktop(currentSmallVideo.peerJid); - // Change the way we'll be measuring and positioning large video - - getVideoSize = isDesktop - ? getDesktopVideoSize - : getCameraVideoSize; - getVideoPosition = isDesktop - ? getDesktopVideoPosition - : getCameraVideoPosition; - - - // Only if the large video is currently visible. - if (isVisible) { - LargeVideo.VideoLayout.largeVideoUpdated(currentSmallVideo); - - $('#largeVideo').fadeIn(300); - } -} - -/** - * Creates the html elements for the large video. - */ -function createLargeVideoHTML() -{ - var html = '
'; - html += '
' + - '
' + - '
' + - '
' + - '' + - ' jitsi.org' + - ''+ - '
' + - '' + - '' + - '
' + - ''; - html += '
'; - $(html).prependTo("#videospace"); - - if (interfaceConfig.SHOW_JITSI_WATERMARK) { - var leftWatermarkDiv - = $("#largeVideoContainer div[class='watermark leftwatermark']"); - - leftWatermarkDiv.css({display: 'block'}); - leftWatermarkDiv.parent().get(0).href - = interfaceConfig.JITSI_WATERMARK_LINK; - } - - if (interfaceConfig.SHOW_BRAND_WATERMARK) { - var rightWatermarkDiv - = $("#largeVideoContainer div[class='watermark rightwatermark']"); - - rightWatermarkDiv.css({display: 'block'}); - rightWatermarkDiv.parent().get(0).href - = interfaceConfig.BRAND_WATERMARK_LINK; - rightWatermarkDiv.get(0).style.backgroundImage - = "url(images/rightwatermark.png)"; - } - - if (interfaceConfig.SHOW_POWERED_BY) { - $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'}); - } - - if (!RTCBrowserType.isIExplorer()) { - $('#largeVideo').volume = 0; - } -} - -var LargeVideo = { - - init: function (VideoLayout, emitter) { - if(!isEnabled) - return; - createLargeVideoHTML(); - - this.VideoLayout = VideoLayout; - this.eventEmitter = emitter; - this.eventEmitter.emit(UIEvents.LARGEVIDEO_INIT); - var self = this; - // Listen for large video size updates - var largeVideo = $('#largeVideo')[0]; - var onplaying = function (arg1, arg2, arg3) { - // re-select - if (RTCBrowserType.isTemasysPluginUsed()) - largeVideo = $('#largeVideo')[0]; - currentVideoWidth = largeVideo.videoWidth; - currentVideoHeight = largeVideo.videoHeight; - self.position(currentVideoWidth, currentVideoHeight); - }; - largeVideo.onplaying = onplaying; - }, - /** - * Indicates if the large video is currently visible. - * - * @return true if visible, false - otherwise - */ - isLargeVideoVisible: function() { - return $('#largeVideo').is(':visible'); - }, - /** - * Returns true if the user is currently displayed on large video. - */ - isCurrentlyOnLarge: function (resourceJid) { - return currentSmallVideo && resourceJid && - currentSmallVideo.getResourceJid() === resourceJid; - }, - /** - * Updates the large video with the given new video source. - */ - updateLargeVideo: function (resourceJid, forceUpdate) { - if(!isEnabled) - return; - var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid); - console.log('hover in ' + resourceJid + ', video: ', newSmallVideo); - - if (!LargeVideo.isCurrentlyOnLarge(resourceJid) || forceUpdate) { - $('#activeSpeaker').css('visibility', 'hidden'); - - var oldSmallVideo = null; - if (currentSmallVideo) { - oldSmallVideo = currentSmallVideo; - } - currentSmallVideo = newSmallVideo; - - var oldJid = null; - if (oldSmallVideo) - oldJid = oldSmallVideo.peerJid; - if (oldJid !== resourceJid) { - // we want the notification to trigger even if userJid is undefined, - // or null. - this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, resourceJid); - } - if (RTCBrowserType.isSafari()) { - // FIXME In Safari fadeOut works only for the first time - changeVideo(this.isLargeVideoVisible()); - } else { - $('#largeVideo').fadeOut(300, - changeVideo.bind($('#largeVideo'), this.isLargeVideoVisible())); - } - } else { - if (currentSmallVideo) { - currentSmallVideo.showAvatar(); - } - } - - }, - - /** - * Shows/hides the large video. - */ - setLargeVideoVisible: function(isVisible) { - if(!isEnabled) - return; - if (isVisible) { - $('#largeVideo').css({visibility: 'visible'}); - $('.watermark').css({visibility: 'visible'}); - if(currentSmallVideo) - currentSmallVideo.enableDominantSpeaker(true); - } - else { - $('#largeVideo').css({visibility: 'hidden'}); - $('#activeSpeaker').css('visibility', 'hidden'); - $('.watermark').css({visibility: 'hidden'}); - if(currentSmallVideo) - currentSmallVideo.enableDominantSpeaker(false); - } - }, - onVideoTypeChanged: function (jid) { - if(!isEnabled) - return; - var resourceJid = Strophe.getResourceFromJid(jid); - if (LargeVideo.isCurrentlyOnLarge(resourceJid)) - { - var isDesktop = APP.RTC.isVideoSrcDesktop(jid); - getVideoSize = isDesktop - ? getDesktopVideoSize - : getCameraVideoSize; - getVideoPosition = isDesktop - ? getDesktopVideoPosition - : getCameraVideoPosition; - this.position(null, null); - } - }, - /** - * Positions the large video. - * - * @param videoWidth the stream video width - * @param videoHeight the stream video height - */ - position: function (videoWidth, videoHeight, - videoSpaceWidth, videoSpaceHeight, animate) { - if(!isEnabled) - return; - if(!videoSpaceWidth) - videoSpaceWidth = $('#videospace').width(); - if(!videoSpaceHeight) - videoSpaceHeight = window.innerHeight; - - var videoSize = getVideoSize(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight); - - var largeVideoWidth = videoSize[0]; - var largeVideoHeight = videoSize[1]; - - var videoPosition = getVideoPosition(largeVideoWidth, - largeVideoHeight, - videoSpaceWidth, - videoSpaceHeight); - - var horizontalIndent = videoPosition[0]; - var verticalIndent = videoPosition[1]; - - positionVideo($('#largeVideo'), - largeVideoWidth, - largeVideoHeight, - horizontalIndent, verticalIndent, animate); - }, - resize: function (animate, isVisible, completeFunction) { - if(!isEnabled) - return; - var availableHeight = window.innerHeight; - var availableWidth = UIUtil.getAvailableVideoWidth(isVisible); - - if (availableWidth < 0 || availableHeight < 0) return; - - var avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE; - var top = availableHeight / 2 - avatarSize / 4 * 3; - $('#activeSpeaker').css('top', top); - - if(animate) - { - $('#videospace').animate({ - right: window.innerWidth - availableWidth, - width: availableWidth, - height: availableHeight - }, - { - queue: false, - duration: 500, - complete: completeFunction - }); - - $('#largeVideoContainer').animate({ - width: availableWidth, - height: availableHeight - }, - { - queue: false, - duration: 500 - }); - - - } - else - { - $('#videospace').width(availableWidth); - $('#videospace').height(availableHeight); - $('#largeVideoContainer').width(availableWidth); - $('#largeVideoContainer').height(availableHeight); - } - return [availableWidth, availableHeight]; - - }, - resizeVideoAreaAnimated: function (isVisible, completeFunction) { - if(!isEnabled) - return; - var size = this.resize(true, isVisible, completeFunction); - this.position(null, null, size[0], size[1], true); - }, - getResourceJid: function () { - return currentSmallVideo ? currentSmallVideo.getResourceJid() : null; - }, - updateAvatar: function (resourceJid) { - if(!isEnabled) - return; - if (resourceJid === this.getResourceJid()) { - updateActiveSpeakerAvatarSrc(); - } - }, - showAvatar: function (resourceJid, show) { - if(!isEnabled) - return; - if(this.getResourceJid() === resourceJid - && state === "video") - { - $("#largeVideo").css("visibility", show ? "hidden" : "visible"); - $('#activeSpeaker').css("visibility", show ? "visible" : "hidden"); - return true; - } - return false; - }, - /** - * Disables the large video - */ - disable: function () { - isEnabled = false; - }, - /** - * Enables the large video - */ - enable: function () { - isEnabled = true; - }, - /** - * Returns true if the video is enabled. - */ - isEnabled: function () { - return isEnabled; - }, - /** - * Creates the iframe used by the etherpad - * @param src the value for src attribute - * @param onloadHandler handler executed when the iframe loads it content - * @returns {HTMLElement} the iframe - */ - createEtherpadIframe: function (src, onloadHandler) { - if(!isEnabled) - return; - - var etherpadIFrame = document.createElement('iframe'); - etherpadIFrame.src = src; - etherpadIFrame.frameBorder = 0; - etherpadIFrame.scrolling = "no"; - etherpadIFrame.width = $('#largeVideoContainer').width() || 640; - etherpadIFrame.height = $('#largeVideoContainer').height() || 480; - etherpadIFrame.setAttribute('style', 'visibility: hidden;'); - - document.getElementById('etherpad').appendChild(etherpadIFrame); - - etherpadIFrame.onload = onloadHandler; - - return etherpadIFrame; - }, - /** - * Changes the state of the large video. - * Possible values - video, prezi, etherpad. - * @param newState - the new state - */ - setState: function (newState) { - if(state === newState) - return; - var currentContainer = getContainerByState(state); - if(!currentContainer) - return; - - var self = this; - var oldState = state; - - switch (newState) - { - case "etherpad": - $('#activeSpeaker').css('visibility', 'hidden'); - currentContainer.fadeOut(300, function () { - if (oldState === "prezi") { - currentContainer.css({opacity: '0'}); - $('#reloadPresentation').css({display: 'none'}); - } - else { - self.setLargeVideoVisible(false); - } - }); - - $('#etherpad>iframe').fadeIn(300, function () { - document.body.style.background = '#eeeeee'; - $('#etherpad>iframe').css({visibility: 'visible'}); - $('#etherpad').css({zIndex: 2}); - }); - break; - case "prezi": - var prezi = $('#presentation>iframe'); - currentContainer.fadeOut(300, function() { - document.body.style.background = 'black'; - }); - prezi.fadeIn(300, function() { - prezi.css({opacity:'1'}); - ToolbarToggler.dockToolbar(true);//fix that - self.setLargeVideoVisible(false); - $('#etherpad>iframe').css({visibility: 'hidden'}); - $('#etherpad').css({zIndex: 0}); - }); - $('#activeSpeaker').css('visibility', 'hidden'); - break; - - case "video": - currentContainer.fadeOut(300, function () { - $('#presentation>iframe').css({opacity:'0'}); - $('#reloadPresentation').css({display:'none'}); - $('#etherpad>iframe').css({visibility: 'hidden'}); - $('#etherpad').css({zIndex: 0}); - document.body.style.background = 'black'; - ToolbarToggler.dockToolbar(false);//fix that - }); - $('#largeVideo').fadeIn(300, function () { - self.setLargeVideoVisible(true); - }); - break; - } - - state = newState; - - }, - /** - * Returns the current state of the large video. - * @returns {string} the current state - video, prezi or etherpad. - */ - getState: function () { - return state; - }, - /** - * Sets hover handlers for the large video container div. - * @param inHandler - * @param outHandler - */ - setHover: function(inHandler, outHandler) - { - $('#largeVideoContainer').hover(inHandler, outHandler); - } - -}; - - -module.exports = LargeVideo; -},{"../../../service/UI/UIEvents":104,"../../RTC/RTCBrowserType":10,"../../xmpp/xmpp":68,"../avatar/Avatar":18,"../toolbars/ToolbarToggler":31,"../util/UIUtil":35}],38:[function(require,module,exports){ -var SmallVideo = require("./SmallVideo"); -var ConnectionIndicator = require("./ConnectionIndicator"); -var NicknameHandler = require("../util/NicknameHandler"); -var UIUtil = require("../util/UIUtil"); -var LargeVideo = require("./LargeVideo"); -var RTCBrowserType = require("../../RTC/RTCBrowserType"); - -function LocalVideo(VideoLayout) -{ - this.videoSpanId = "localVideoContainer"; - this.container = $("#localVideoContainer").get(0); - this.VideoLayout = VideoLayout; - this.flipX = true; - this.isLocal = true; - this.peerJid = null; -} - -LocalVideo.prototype = Object.create(SmallVideo.prototype); -LocalVideo.prototype.constructor = LocalVideo; - -/** - * Creates the edit display name button. - * - * @returns the edit button - */ -function createEditDisplayNameButton() { - var editButton = document.createElement('a'); - editButton.className = 'displayname'; - UIUtil.setTooltip(editButton, - "videothumbnail.editnickname", - "top"); - editButton.innerHTML = ''; - - return editButton; -} - - -/** - * Sets the display name for the given video span id. - */ -LocalVideo.prototype.setDisplayName = function(displayName, key) { - - if (!this.container) { - console.warn( - "Unable to set displayName - " + this.videoSpanId + " does not exist"); - return; - } - - var nameSpan = $('#' + this.videoSpanId + '>span.displayname'); - var defaultLocalDisplayName = APP.translation.generateTranslationHTML( - interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME); - - // If we already have a display name for this video. - if (nameSpan.length > 0) { - - if (nameSpan.text() !== displayName) { - if (displayName && displayName.length > 0) - { - var meHTML = APP.translation.generateTranslationHTML("me"); - $('#localDisplayName').html(displayName + ' (' + meHTML + ')'); - } - else - $('#localDisplayName').html(defaultLocalDisplayName); - } - } else { - var editButton = createEditDisplayNameButton(); - - nameSpan = document.createElement('span'); - nameSpan.className = 'displayname'; - $('#' + this.videoSpanId)[0].appendChild(nameSpan); - - - if (displayName && displayName.length > 0) { - var meHTML = APP.translation.generateTranslationHTML("me"); - nameSpan.innerHTML = displayName + meHTML; - } - else { - nameSpan.innerHTML = defaultLocalDisplayName; - } - - - nameSpan.id = 'localDisplayName'; - this.container.appendChild(editButton); - //translates popover of edit button - APP.translation.translateElement($("a.displayname")); - - var editableText = document.createElement('input'); - editableText.className = 'displayname'; - editableText.type = 'text'; - editableText.id = 'editDisplayName'; - - if (displayName && displayName.length) { - editableText.value = displayName; - } - - var defaultNickname = APP.translation.translateString( - "defaultNickname", {name: "Jane Pink"}); - editableText.setAttribute('style', 'display:none;'); - editableText.setAttribute('data-18n', - '[placeholder]defaultNickname'); - editableText.setAttribute("data-i18n-options", - JSON.stringify({name: "Jane Pink"})); - editableText.setAttribute("placeholder", defaultNickname); - - this.container.appendChild(editableText); - - var self = this; - $('#localVideoContainer .displayname') - .bind("click", function (e) { - - e.preventDefault(); - e.stopPropagation(); - $('#localDisplayName').hide(); - $('#editDisplayName').show(); - $('#editDisplayName').focus(); - $('#editDisplayName').select(); - - $('#editDisplayName').one("focusout", function (e) { - self.VideoLayout.inputDisplayNameHandler(this.value); - }); - - $('#editDisplayName').on('keydown', function (e) { - if (e.keyCode === 13) { - e.preventDefault(); - self.VideoLayout.inputDisplayNameHandler(this.value); - } - }); - }); - } -} - -LocalVideo.prototype.inputDisplayNameHandler = function (name) { - NicknameHandler.setNickname(name); - - if (!$('#localDisplayName').is(":visible")) { - if (NicknameHandler.getNickname()) - { - var meHTML = APP.translation.generateTranslationHTML("me"); - $('#localDisplayName').html(NicknameHandler.getNickname() + " (" + meHTML + ")"); - } - else - { - var defaultHTML = APP.translation.generateTranslationHTML( - interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME); - $('#localDisplayName') - .html(defaultHTML); - } - $('#localDisplayName').show(); - } - - $('#editDisplayName').hide(); -} - -LocalVideo.prototype.createConnectionIndicator = function() -{ - if(this.connectionIndicator) - return; - - this.connectionIndicator - = new ConnectionIndicator(this, null); -} - -LocalVideo.prototype.changeVideo = function (stream, isMuted) { - var self = this; - - function localVideoClick(event) { - // FIXME: with Temasys plugin event arg is not an event, but - // the clicked object itself, so we have to skip this call - if (event.stopPropagation) { - event.stopPropagation(); - } - self.VideoLayout.handleVideoThumbClicked( - false, - APP.xmpp.myResource()); - } - - $('#localVideoContainer').off('click'); - $('#localVideoContainer').on('click', localVideoClick); - - // Add hover handler - $('#localVideoContainer').hover( - function() { - self.showDisplayName(true); - }, - function() { - if (!LargeVideo.isLargeVideoVisible() || - !LargeVideo.isCurrentlyOnLarge(self.getResourceJid())) - self.showDisplayName(false); - } - ); - - if(isMuted) - { - APP.UI.setVideoMute(true); - return; - } - this.flipX = (stream.videoType == "screen")? false : true; - var localVideo = document.createElement('video'); - localVideo.id = 'localVideo_' + - APP.RTC.getStreamID(stream.getOriginalStream()); - if (!RTCBrowserType.isIExplorer()) { - localVideo.autoplay = true; - localVideo.volume = 0; // is it required if audio is separated ? - } - localVideo.oncontextmenu = function () { return false; }; - - var localVideoContainer = document.getElementById('localVideoWrapper'); - localVideoContainer.appendChild(localVideo); - - var localVideoSelector = $('#' + localVideo.id); - - // Add click handler to both video and video wrapper elements in case - // there's no video. - - // onclick has to be used with Temasys plugin - localVideo.onclick = localVideoClick; - - if (this.flipX) { - localVideoSelector.addClass("flipVideoX"); - } - - // Attach WebRTC stream - APP.RTC.attachMediaStream(localVideoSelector, stream.getOriginalStream()); - - // Add stream ended handler - stream.getOriginalStream().onended = function () { - // We have to re-select after attach when Temasys plugin is used, - // because