diff --git a/app.js b/app.js
index 61bbf63bc..716b3ae5b 100644
--- a/app.js
+++ b/app.js
@@ -41,6 +41,9 @@ const Commands = {
CONNECTION_QUALITY: "connectionQuality",
EMAIL: "email",
VIDEO_TYPE: "videoType"
+ ETHERPAD: "etherpad",
+ PREZI: "prezi",
+ STOP_PREZI: "stop-prezi"
};
function buildRoomName () {
@@ -218,16 +221,14 @@ function initConference(localTracks, connection) {
room.on(ConferenceEvents.USER_JOINED, function (id, user) {
- if (APP.conference.isLocalId(id)) {
- return;
- }
- console.error('USER %s connnected', id);
+ console.error('USER %s connnected', id, user);
// FIXME email???
APP.UI.addUser(id, user.getDisplayName());
});
room.on(ConferenceEvents.USER_LEFT, function (id, user) {
- console.error('USER LEFT', id);
+ console.error('USER %s LEFT', id, user);
APP.UI.removeUser(id, user.getDisplayName());
+ APP.UI.stopPrezi(id);
});
@@ -348,9 +349,12 @@ function initConference(localTracks, connection) {
room.removeCommand(Commands.CONNECTION_QUALITY);
});
// listen to remote stats
- room.addCommandListener(Commands.CONNECTION_QUALITY, function (data) {
- APP.connectionquality.updateRemoteStats(data.attributes.id, data.value);
- });
+ room.addCommandListener(
+ Commands.CONNECTION_QUALITY,
+ function ({value, attributes}) {
+ APP.connectionquality.updateRemoteStats(attributes.id, value);
+ }
+ );
APP.connectionquality.addListener(
CQEvents.REMOTESTATS_UPDATED,
function (id, percent, stats) {
@@ -358,6 +362,37 @@ function initConference(localTracks, connection) {
}
);
+ room.addCommandListener(Commands.ETHERPAD, function ({value}) {
+ APP.UI.initEtherpad(value);
+ });
+
+
+ room.addCommandListener(Commands.PREZI, function ({value, attributes}) {
+ APP.UI.showPrezi(attributes.id, value, attributes.slide);
+ });
+ room.addCommandListener(Commands.STOP_PREZI, function ({attributes}) {
+ APP.UI.stopPrezi(attributes.id);
+ });
+ APP.UI.addListener(UIEvents.SHARE_PREZI, function (url, slide) {
+ console.log('Sharing Prezi %s slide %s', url, slide);
+ room.removeCommand(Commands.PREZI);
+ room.sendCommand(Commands.PREZI, {
+ value: url,
+ attributes: {
+ id: room.myUserId(),
+ slide
+ }
+ });
+ });
+ APP.UI.addListener(UIEvents.STOP_SHARING_PREZI, function () {
+ room.removeCommand(Commands.PREZI);
+ room.sendCommandOnce(Commands.STOP_PREZI, {
+ attributes: {
+ id: room.myUserId()
+ }
+ });
+ });
+
room.addCommandListener(Commands.VIDEO_TYPE, (data, from) => {
APP.UI.onPeerVideoTypeChanged(from, data.value);
});
diff --git a/css/videolayout_default.css b/css/videolayout_default.css
index 02a71eafa..2935fcab9 100644
--- a/css/videolayout_default.css
+++ b/css/videolayout_default.css
@@ -34,7 +34,7 @@
}
#remoteVideos .videocontainer {
- display: inline-block;
+ display: none;
background-color: black;
background-size: contain;
border-radius:8px;
@@ -378,7 +378,7 @@
padding-right:2px;
height:38px;
width:auto;
- background-color: rgba(0,0,0,0.8);
+ background-color: rgba(0,0,0,0.8);
border: 1px solid rgba(256, 256, 256, 0.2);
border-radius: 6px;
pointer-events: auto;
diff --git a/index.html b/index.html
index 8790e2d8d..ecd1c37fc 100644
--- a/index.html
+++ b/index.html
@@ -140,6 +140,25 @@
+
+
+
diff --git a/libs/lib-jitsi-meet.js b/libs/lib-jitsi-meet.js
index fd5ab62f4..76532fb5a 100644
--- a/libs/lib-jitsi-meet.js
+++ b/libs/lib-jitsi-meet.js
@@ -403,7 +403,7 @@ JitsiConference.prototype.kickParticipant = function (id) {
JitsiConference.prototype.onMemberJoined = function (jid, email, nick) {
var id = Strophe.getResourceFromJid(jid);
- if (id === 'focus') {
+ if (id === 'focus' || this.myUserId() === id) {
return;
}
var participant = new JitsiParticipant(jid, this, nick);
@@ -579,15 +579,6 @@ JitsiConference.prototype.toggleRecording = function (token, followEntity) {
reject(new Error("The conference is not created yet!"))});
}
-/**
- * Returns true if the SIP calls are supported and false otherwise
- */
-JitsiConference.prototype.isSIPCallingSupported = function () {
- if(this.room)
- return this.room.isSIPCallingSupported();
- return false;
-}
-
/**
* Dials a number.
* @param number the number
@@ -1068,13 +1059,6 @@ var LibJitsiMeet = {
init: function (options) {
return RTC.init(options || {});
},
- /**
- * Returns whether the desktop sharing is enabled or not.
- * @returns {boolean}
- */
- isDesktopSharingEnabled: function () {
- return RTC.isDesktopSharingEnabled();
- },
setLogLevel: function (level) {
Logger.setLogLevel(level);
},
@@ -1815,7 +1799,6 @@ module.exports = JitsiRemoteTrack;
var RTCBrowserType = require("./RTCBrowserType");
var JitsiTrackEvents = require("../../JitsiTrackEvents");
var EventEmitter = require("events");
-var RTC = require("./RTCUtils");
/**
* This implements 'onended' callback normally fired by WebRTC after the stream
@@ -2006,21 +1989,13 @@ JitsiTrack.prototype.isScreenSharing = function(){
* Returns id of the track.
* @returns {string} id of the track or null if this is fake track.
*/
-JitsiTrack.prototype._getId = function () {
+JitsiTrack.prototype.getId = function () {
var tracks = this.stream.getTracks();
if(!tracks || tracks.length === 0)
return null;
return tracks[0].id;
};
-/**
- * Returns id of the track.
- * @returns {string} id of the track or null if this is fake track.
- */
-JitsiTrack.prototype.getId = function () {
- return RTC.getStreamID(this.stream);
-};
-
/**
* Checks whether the MediaStream is avtive/not ended.
* When there is no check for active we don't have information and so
@@ -2272,14 +2247,6 @@ RTC.stopMediaStream = function (mediaStream) {
RTCUtils.stopMediaStream(mediaStream);
};
-/**
- * Returns whether the desktop sharing is enabled or not.
- * @returns {boolean}
- */
-RTC.isDesktopSharingEnabled = function () {
- return RTCUtils.isDesktopSharingEnabled();
-}
-
RTC.prototype.getVideoElementName = function () {
return RTCBrowserType.isTemasysPluginUsed() ? 'object' : 'video';
};
@@ -3138,7 +3105,7 @@ var RTCUtils = {
var deviceGUM = {
"audio": GUM.bind(self, ["audio"]),
"video": GUM.bind(self, ["video"]),
- "desktop": screenObtainer.obtainStream.bind(screenObtainer)
+ "desktop": screenObtainer.obtainStream
};
// 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
@@ -3244,13 +3211,6 @@ var RTCUtils = {
if (mediaStream.stop) {
mediaStream.stop();
}
- },
- /**
- * Returns whether the desktop sharing is enabled or not.
- * @returns {boolean}
- */
- isDesktopSharingEnabled: function () {
- return screenObtainer.isSupported();
}
};
@@ -6384,7 +6344,7 @@ ChatRoom.prototype.onPresence = function (pres) {
ChatRoom.prototype.processNode = function (node, from) {
if(this.presHandlers[node.tagName])
- this.presHandlers[node.tagName](node, Strophe.getResourceFromJid(from));
+ this.presHandlers[node.tagName](node, from);
};
ChatRoom.prototype.sendMessage = function (body, nickname) {
@@ -6762,15 +6722,6 @@ ChatRoom.prototype.toggleRecording = function (token, followEntity) {
reject(new Error("The conference is not created yet!"))});
}
-/**
- * Returns true if the SIP calls are supported and false otherwise
- */
-ChatRoom.prototype.isSIPCallingSupported = function () {
- if(this.moderator)
- return this.moderator.isSipGatewayEnabled();
- return false;
-}
-
/**
* Dials a number.
* @param number the number
@@ -9137,11 +9088,11 @@ SDP.prototype.toJingle = function (elem, thecreator) {
var msid = null;
if(mline.media == "audio")
{
- msid = APP.RTC.localAudio._getId();
+ msid = APP.RTC.localAudio.getId();
}
else
{
- msid = APP.RTC.localVideo._getId();
+ msid = APP.RTC.localVideo.getId();
}
if(msid != null)
{
@@ -9537,6 +9488,7 @@ SDP.prototype.jingle2media = function (content) {
module.exports = SDP;
+
}).call(this,"/modules/xmpp/SDP.js")
},{"./SDPUtil":32,"jitsi-meet-logger":48}],31:[function(require,module,exports){
var SDPUtil = require("./SDPUtil");
@@ -10528,7 +10480,7 @@ TraceablePeerConnection.prototype.getStats = function(callback, errback) {
module.exports = TraceablePeerConnection;
}).call(this,"/modules/xmpp/TraceablePeerConnection.js")
-},{"../../service/xmpp/XMPPEvents":87,"../RTC/RTC":16,"../RTC/RTCBrowserType.js":17,"./LocalSSRCReplacement":29,"jitsi-meet-logger":48,"sdp-interop":66,"sdp-simulcast":73,"sdp-transform":76}],34:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":87,"../RTC/RTC":16,"../RTC/RTCBrowserType.js":17,"./LocalSSRCReplacement":29,"jitsi-meet-logger":48,"sdp-interop":66,"sdp-simulcast":69,"sdp-transform":76}],34:[function(require,module,exports){
(function (__filename){
/* global $, $iq, APP, config, messageHandler,
roomName, sessionTerminated, Strophe, Util */
@@ -10570,7 +10522,7 @@ function Moderator(roomName, xmpp, emitter) {
// Sip gateway can be enabled by configuring Jigasi host in config.js or
// it will be enabled automatically if focus detects the component through
// service discovery.
- this.sipGatewayEnabled = this.xmppService.options.hosts &&
+ this.sipGatewayEnabled =
this.xmppService.options.hosts.call_control !== undefined;
this.eventEmitter = emitter;
@@ -22181,487 +22133,7 @@ exports.parse = function(sdp) {
};
-},{"sdp-transform":70}],69:[function(require,module,exports){
-var grammar = module.exports = {
- v: [{
- name: 'version',
- reg: /^(\d*)$/
- }],
- o: [{ //o=- 20518 0 IN IP4 203.0.113.1
- // NB: sessionId will be a String in most cases because it is huge
- name: 'origin',
- reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
- names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
- format: "%s %s %d %s IP%d %s"
- }],
- // default parsing of these only (though some of these feel outdated)
- s: [{ name: 'name' }],
- i: [{ name: 'description' }],
- u: [{ name: 'uri' }],
- e: [{ name: 'email' }],
- p: [{ name: 'phone' }],
- z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
- r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
- //k: [{}], // outdated thing ignored
- t: [{ //t=0 0
- name: 'timing',
- reg: /^(\d*) (\d*)/,
- names: ['start', 'stop'],
- format: "%d %d"
- }],
- c: [{ //c=IN IP4 10.47.197.26
- name: 'connection',
- reg: /^IN IP(\d) (\S*)/,
- names: ['version', 'ip'],
- format: "IN IP%d %s"
- }],
- b: [{ //b=AS:4000
- push: 'bandwidth',
- reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
- names: ['type', 'limit'],
- format: "%s:%s"
- }],
- m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
- // NB: special - pushes to session
- // TODO: rtp/fmtp should be filtered by the payloads found here?
- reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
- names: ['type', 'port', 'protocol', 'payloads'],
- format: "%s %d %s %s"
- }],
- a: [
- { //a=rtpmap:110 opus/48000/2
- push: 'rtp',
- reg: /^rtpmap:(\d*) ([\w\-]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
- names: ['payload', 'codec', 'rate', 'encoding'],
- format: function (o) {
- return (o.encoding) ?
- "rtpmap:%d %s/%s/%s":
- o.rate ?
- "rtpmap:%d %s/%s":
- "rtpmap:%d %s";
- }
- },
- {
- //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
- //a=fmtp:111 minptime=10; useinbandfec=1
- push: 'fmtp',
- reg: /^fmtp:(\d*) ([\S| ]*)/,
- names: ['payload', 'config'],
- format: "fmtp:%d %s"
- },
- { //a=control:streamid=0
- name: 'control',
- reg: /^control:(.*)/,
- format: "control:%s"
- },
- { //a=rtcp:65179 IN IP4 193.84.77.194
- name: 'rtcp',
- reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
- names: ['port', 'netType', 'ipVer', 'address'],
- format: function (o) {
- return (o.address != null) ?
- "rtcp:%d %s IP%d %s":
- "rtcp:%d";
- }
- },
- { //a=rtcp-fb:98 trr-int 100
- push: 'rtcpFbTrrInt',
- reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
- names: ['payload', 'value'],
- format: "rtcp-fb:%d trr-int %d"
- },
- { //a=rtcp-fb:98 nack rpsi
- push: 'rtcpFb',
- reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
- names: ['payload', 'type', 'subtype'],
- format: function (o) {
- return (o.subtype != null) ?
- "rtcp-fb:%s %s %s":
- "rtcp-fb:%s %s";
- }
- },
- { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
- //a=extmap:1/recvonly URI-gps-string
- push: 'ext',
- reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
- names: ['value', 'uri', 'config'], // value may include "/direction" suffix
- format: function (o) {
- return (o.config != null) ?
- "extmap:%s %s %s":
- "extmap:%s %s";
- }
- },
- {
- //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
- push: 'crypto',
- reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
- names: ['id', 'suite', 'config', 'sessionConfig'],
- format: function (o) {
- return (o.sessionConfig != null) ?
- "crypto:%d %s %s %s":
- "crypto:%d %s %s";
- }
- },
- { //a=setup:actpass
- name: 'setup',
- reg: /^setup:(\w*)/,
- format: "setup:%s"
- },
- { //a=mid:1
- name: 'mid',
- reg: /^mid:([^\s]*)/,
- format: "mid:%s"
- },
- { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
- name: 'msid',
- reg: /^msid:(.*)/,
- format: "msid:%s"
- },
- { //a=ptime:20
- name: 'ptime',
- reg: /^ptime:(\d*)/,
- format: "ptime:%d"
- },
- { //a=maxptime:60
- name: 'maxptime',
- reg: /^maxptime:(\d*)/,
- format: "maxptime:%d"
- },
- { //a=sendrecv
- name: 'direction',
- reg: /^(sendrecv|recvonly|sendonly|inactive)/
- },
- { //a=ice-lite
- name: 'icelite',
- reg: /^(ice-lite)/
- },
- { //a=ice-ufrag:F7gI
- name: 'iceUfrag',
- reg: /^ice-ufrag:(\S*)/,
- format: "ice-ufrag:%s"
- },
- { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
- name: 'icePwd',
- reg: /^ice-pwd:(\S*)/,
- format: "ice-pwd:%s"
- },
- { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
- name: 'fingerprint',
- reg: /^fingerprint:(\S*) (\S*)/,
- names: ['type', 'hash'],
- format: "fingerprint:%s %s"
- },
- {
- //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
- //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
- //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
- //a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0
- //a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0
- push:'candidates',
- reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?/,
- names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation'],
- format: function (o) {
- var str = "candidate:%s %d %s %d %s %d typ %s";
-
- str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
-
- // NB: candidate has three optional chunks, so %void middles one if it's missing
- str += (o.tcptype != null) ? " tcptype %s" : "%v";
-
- if (o.generation != null) {
- str += " generation %d";
- }
- return str;
- }
- },
- { //a=end-of-candidates (keep after the candidates line for readability)
- name: 'endOfCandidates',
- reg: /^(end-of-candidates)/
- },
- { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
- name: 'remoteCandidates',
- reg: /^remote-candidates:(.*)/,
- format: "remote-candidates:%s"
- },
- { //a=ice-options:google-ice
- name: 'iceOptions',
- reg: /^ice-options:(\S*)/,
- format: "ice-options:%s"
- },
- { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
- push: "ssrcs",
- reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
- names: ['id', 'attribute', 'value'],
- format: "ssrc:%d %s:%s"
- },
- { //a=ssrc-group:FEC 1 2
- push: "ssrcGroups",
- reg: /^ssrc-group:(\w*) (.*)/,
- names: ['semantics', 'ssrcs'],
- format: "ssrc-group:%s %s"
- },
- { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
- name: "msidSemantic",
- reg: /^msid-semantic:\s?(\w*) (\S*)/,
- names: ['semantic', 'token'],
- format: "msid-semantic: %s %s" // space after ":" is not accidental
- },
- { //a=group:BUNDLE audio video
- push: 'groups',
- reg: /^group:(\w*) (.*)/,
- names: ['type', 'mids'],
- format: "group:%s %s"
- },
- { //a=rtcp-mux
- name: 'rtcpMux',
- reg: /^(rtcp-mux)/
- },
- { //a=rtcp-rsize
- name: 'rtcpRsize',
- reg: /^(rtcp-rsize)/
- },
- { // any a= that we don't understand is kepts verbatim on media.invalid
- push: 'invalid',
- names: ["value"]
- }
- ]
-};
-
-// set sensible defaults to avoid polluting the grammar with boring details
-Object.keys(grammar).forEach(function (key) {
- var objs = grammar[key];
- objs.forEach(function (obj) {
- if (!obj.reg) {
- obj.reg = /(.*)/;
- }
- if (!obj.format) {
- obj.format = "%s";
- }
- });
-});
-
-},{}],70:[function(require,module,exports){
-var parser = require('./parser');
-var writer = require('./writer');
-
-exports.write = writer;
-exports.parse = parser.parse;
-exports.parseFmtpConfig = parser.parseFmtpConfig;
-exports.parsePayloads = parser.parsePayloads;
-exports.parseRemoteCandidates = parser.parseRemoteCandidates;
-
-},{"./parser":71,"./writer":72}],71:[function(require,module,exports){
-var toIntIfInt = function (v) {
- return String(Number(v)) === v ? Number(v) : v;
-};
-
-var attachProperties = function (match, location, names, rawName) {
- if (rawName && !names) {
- location[rawName] = toIntIfInt(match[1]);
- }
- else {
- for (var i = 0; i < names.length; i += 1) {
- if (match[i+1] != null) {
- location[names[i]] = toIntIfInt(match[i+1]);
- }
- }
- }
-};
-
-var parseReg = function (obj, location, content) {
- var needsBlank = obj.name && obj.names;
- if (obj.push && !location[obj.push]) {
- location[obj.push] = [];
- }
- else if (needsBlank && !location[obj.name]) {
- location[obj.name] = {};
- }
- var keyLocation = obj.push ?
- {} : // blank object that will be pushed
- needsBlank ? location[obj.name] : location; // otherwise, named location or root
-
- attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
-
- if (obj.push) {
- location[obj.push].push(keyLocation);
- }
-};
-
-var grammar = require('./grammar');
-var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
-
-exports.parse = function (sdp) {
- var session = {}
- , media = []
- , location = session; // points at where properties go under (one of the above)
-
- // parse lines we understand
- sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
- var type = l[0];
- var content = l.slice(2);
- if (type === 'm') {
- media.push({rtp: [], fmtp: []});
- location = media[media.length-1]; // point at latest media line
- }
-
- for (var j = 0; j < (grammar[type] || []).length; j += 1) {
- var obj = grammar[type][j];
- if (obj.reg.test(content)) {
- return parseReg(obj, location, content);
- }
- }
- });
-
- session.media = media; // link it up
- return session;
-};
-
-var fmtpReducer = function (acc, expr) {
- var s = expr.split('=');
- if (s.length === 2) {
- acc[s[0]] = toIntIfInt(s[1]);
- }
- return acc;
-};
-
-exports.parseFmtpConfig = function (str) {
- return str.split(/\;\s?/).reduce(fmtpReducer, {});
-};
-
-exports.parsePayloads = function (str) {
- return str.split(' ').map(Number);
-};
-
-exports.parseRemoteCandidates = function (str) {
- var candidates = [];
- var parts = str.split(' ').map(toIntIfInt);
- for (var i = 0; i < parts.length; i += 3) {
- candidates.push({
- component: parts[i],
- ip: parts[i + 1],
- port: parts[i + 2]
- });
- }
- return candidates;
-};
-
-},{"./grammar":69}],72:[function(require,module,exports){
-var grammar = require('./grammar');
-
-// customized util.format - discards excess arguments and can void middle ones
-var formatRegExp = /%[sdv%]/g;
-var format = function (formatStr) {
- var i = 1;
- var args = arguments;
- var len = args.length;
- return formatStr.replace(formatRegExp, function (x) {
- if (i >= len) {
- return x; // missing argument
- }
- var arg = args[i];
- i += 1;
- switch (x) {
- case '%%':
- return '%';
- case '%s':
- return String(arg);
- case '%d':
- return Number(arg);
- case '%v':
- return '';
- }
- });
- // NB: we discard excess arguments - they are typically undefined from makeLine
-};
-
-var makeLine = function (type, obj, location) {
- var str = obj.format instanceof Function ?
- (obj.format(obj.push ? location : location[obj.name])) :
- obj.format;
-
- var args = [type + '=' + str];
- if (obj.names) {
- for (var i = 0; i < obj.names.length; i += 1) {
- var n = obj.names[i];
- if (obj.name) {
- args.push(location[obj.name][n]);
- }
- else { // for mLine and push attributes
- args.push(location[obj.names[i]]);
- }
- }
- }
- else {
- args.push(location[obj.name]);
- }
- return format.apply(null, args);
-};
-
-// RFC specified order
-// TODO: extend this with all the rest
-var defaultOuterOrder = [
- 'v', 'o', 's', 'i',
- 'u', 'e', 'p', 'c',
- 'b', 't', 'r', 'z', 'a'
-];
-var defaultInnerOrder = ['i', 'c', 'b', 'a'];
-
-
-module.exports = function (session, opts) {
- opts = opts || {};
- // ensure certain properties exist
- if (session.version == null) {
- session.version = 0; // "v=0" must be there (only defined version atm)
- }
- if (session.name == null) {
- session.name = " "; // "s= " must be there if no meaningful name set
- }
- session.media.forEach(function (mLine) {
- if (mLine.payloads == null) {
- mLine.payloads = "";
- }
- });
-
- var outerOrder = opts.outerOrder || defaultOuterOrder;
- var innerOrder = opts.innerOrder || defaultInnerOrder;
- var sdp = [];
-
- // loop through outerOrder for matching properties on session
- outerOrder.forEach(function (type) {
- grammar[type].forEach(function (obj) {
- if (obj.name in session && session[obj.name] != null) {
- sdp.push(makeLine(type, obj, session));
- }
- else if (obj.push in session && session[obj.push] != null) {
- session[obj.push].forEach(function (el) {
- sdp.push(makeLine(type, obj, el));
- });
- }
- });
- });
-
- // then for each media line, follow the innerOrder
- session.media.forEach(function (mLine) {
- sdp.push(makeLine('m', grammar.m[0], mLine));
-
- innerOrder.forEach(function (type) {
- grammar[type].forEach(function (obj) {
- if (obj.name in mLine && mLine[obj.name] != null) {
- sdp.push(makeLine(type, obj, mLine));
- }
- else if (obj.push in mLine && mLine[obj.push] != null) {
- mLine[obj.push].forEach(function (el) {
- sdp.push(makeLine(type, obj, el));
- });
- }
- });
- });
- });
-
- return sdp.join('\r\n') + '\r\n';
-};
-
-},{"./grammar":69}],73:[function(require,module,exports){
+},{"sdp-transform":76}],69:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22794,7 +22266,7 @@ function explodeRemoteSimulcast(mLine) {
function implodeRemoteSimulcast(mLine) {
if (!mLine || !Array.isArray(mLine.ssrcGroups)) {
- console.info('Halt: There are no SSRC groups in the remote ' +
+ console.debug('Halt: There are no SSRC groups in the remote ' +
'description.');
return;
}
@@ -22807,7 +22279,7 @@ function implodeRemoteSimulcast(mLine) {
return;
}
- console.info("Imploding SIM group: " + simulcastGroup.ssrcs);
+ console.debug("Imploding SIM group: " + simulcastGroup.ssrcs);
// Schedule the SIM group for nuking.
simulcastGroup.nuke = true;
@@ -23081,7 +22553,7 @@ Simulcast.prototype.mungeLocalDescription = function (desc) {
module.exports = Simulcast;
-},{"./transform-utils":74,"sdp-transform":76}],74:[function(require,module,exports){
+},{"./transform-utils":70,"sdp-transform":72}],70:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23147,15 +22619,827 @@ exports.parseSsrcs = function (mLine) {
};
-},{}],75:[function(require,module,exports){
-arguments[4][69][0].apply(exports,arguments)
-},{"dup":69}],76:[function(require,module,exports){
-arguments[4][70][0].apply(exports,arguments)
-},{"./parser":77,"./writer":78,"dup":70}],77:[function(require,module,exports){
-arguments[4][71][0].apply(exports,arguments)
-},{"./grammar":75,"dup":71}],78:[function(require,module,exports){
+},{}],71:[function(require,module,exports){
+var grammar = module.exports = {
+ v: [{
+ name: 'version',
+ reg: /^(\d*)$/
+ }],
+ o: [{ //o=- 20518 0 IN IP4 203.0.113.1
+ // NB: sessionId will be a String in most cases because it is huge
+ name: 'origin',
+ reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
+ names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
+ format: "%s %s %d %s IP%d %s"
+ }],
+ // default parsing of these only (though some of these feel outdated)
+ s: [{ name: 'name' }],
+ i: [{ name: 'description' }],
+ u: [{ name: 'uri' }],
+ e: [{ name: 'email' }],
+ p: [{ name: 'phone' }],
+ z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
+ r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
+ //k: [{}], // outdated thing ignored
+ t: [{ //t=0 0
+ name: 'timing',
+ reg: /^(\d*) (\d*)/,
+ names: ['start', 'stop'],
+ format: "%d %d"
+ }],
+ c: [{ //c=IN IP4 10.47.197.26
+ name: 'connection',
+ reg: /^IN IP(\d) (\S*)/,
+ names: ['version', 'ip'],
+ format: "IN IP%d %s"
+ }],
+ b: [{ //b=AS:4000
+ push: 'bandwidth',
+ reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
+ names: ['type', 'limit'],
+ format: "%s:%s"
+ }],
+ m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
+ // NB: special - pushes to session
+ // TODO: rtp/fmtp should be filtered by the payloads found here?
+ reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
+ names: ['type', 'port', 'protocol', 'payloads'],
+ format: "%s %d %s %s"
+ }],
+ a: [
+ { //a=rtpmap:110 opus/48000/2
+ push: 'rtp',
+ reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
+ names: ['payload', 'codec', 'rate', 'encoding'],
+ format: function (o) {
+ return (o.encoding) ?
+ "rtpmap:%d %s/%s/%s":
+ "rtpmap:%d %s/%s";
+ }
+ },
+ { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
+ push: 'fmtp',
+ reg: /^fmtp:(\d*) (\S*)/,
+ names: ['payload', 'config'],
+ format: "fmtp:%d %s"
+ },
+ { //a=control:streamid=0
+ name: 'control',
+ reg: /^control:(.*)/,
+ format: "control:%s"
+ },
+ { //a=rtcp:65179 IN IP4 193.84.77.194
+ name: 'rtcp',
+ reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
+ names: ['port', 'netType', 'ipVer', 'address'],
+ format: function (o) {
+ return (o.address != null) ?
+ "rtcp:%d %s IP%d %s":
+ "rtcp:%d";
+ }
+ },
+ { //a=rtcp-fb:98 trr-int 100
+ push: 'rtcpFbTrrInt',
+ reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
+ names: ['payload', 'value'],
+ format: "rtcp-fb:%d trr-int %d"
+ },
+ { //a=rtcp-fb:98 nack rpsi
+ push: 'rtcpFb',
+ reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
+ names: ['payload', 'type', 'subtype'],
+ format: function (o) {
+ return (o.subtype != null) ?
+ "rtcp-fb:%s %s %s":
+ "rtcp-fb:%s %s";
+ }
+ },
+ { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+ //a=extmap:1/recvonly URI-gps-string
+ push: 'ext',
+ reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
+ names: ['value', 'uri', 'config'], // value may include "/direction" suffix
+ format: function (o) {
+ return (o.config != null) ?
+ "extmap:%s %s %s":
+ "extmap:%s %s";
+ }
+ },
+ {
+ //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
+ push: 'crypto',
+ reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
+ names: ['id', 'suite', 'config', 'sessionConfig'],
+ format: function (o) {
+ return (o.sessionConfig != null) ?
+ "crypto:%d %s %s %s":
+ "crypto:%d %s %s";
+ }
+ },
+ { //a=setup:actpass
+ name: 'setup',
+ reg: /^setup:(\w*)/,
+ format: "setup:%s"
+ },
+ { //a=mid:1
+ name: 'mid',
+ reg: /^mid:([^\s]*)/,
+ format: "mid:%s"
+ },
+ { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
+ name: 'msid',
+ reg: /^msid:(.*)/,
+ format: "msid:%s"
+ },
+ { //a=ptime:20
+ name: 'ptime',
+ reg: /^ptime:(\d*)/,
+ format: "ptime:%d"
+ },
+ { //a=maxptime:60
+ name: 'maxptime',
+ reg: /^maxptime:(\d*)/,
+ format: "maxptime:%d"
+ },
+ { //a=sendrecv
+ name: 'direction',
+ reg: /^(sendrecv|recvonly|sendonly|inactive)/
+ },
+ { //a=ice-lite
+ name: 'icelite',
+ reg: /^(ice-lite)/
+ },
+ { //a=ice-ufrag:F7gI
+ name: 'iceUfrag',
+ reg: /^ice-ufrag:(\S*)/,
+ format: "ice-ufrag:%s"
+ },
+ { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
+ name: 'icePwd',
+ reg: /^ice-pwd:(\S*)/,
+ format: "ice-pwd:%s"
+ },
+ { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
+ name: 'fingerprint',
+ reg: /^fingerprint:(\S*) (\S*)/,
+ names: ['type', 'hash'],
+ format: "fingerprint:%s %s"
+ },
+ {
+ //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
+ //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
+ //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
+ push:'candidates',
+ reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
+ names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
+ format: function (o) {
+ var str = "candidate:%s %d %s %d %s %d typ %s";
+ // NB: candidate has two optional chunks, so %void middle one if it's missing
+ str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
+ if (o.generation != null) {
+ str += " generation %d";
+ }
+ return str;
+ }
+ },
+ { //a=end-of-candidates (keep after the candidates line for readability)
+ name: 'endOfCandidates',
+ reg: /^(end-of-candidates)/
+ },
+ { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
+ name: 'remoteCandidates',
+ reg: /^remote-candidates:(.*)/,
+ format: "remote-candidates:%s"
+ },
+ { //a=ice-options:google-ice
+ name: 'iceOptions',
+ reg: /^ice-options:(\S*)/,
+ format: "ice-options:%s"
+ },
+ { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
+ push: "ssrcs",
+ reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
+ names: ['id', 'attribute', 'value'],
+ format: "ssrc:%d %s:%s"
+ },
+ { //a=ssrc-group:FEC 1 2
+ push: "ssrcGroups",
+ reg: /^ssrc-group:(\w*) (.*)/,
+ names: ['semantics', 'ssrcs'],
+ format: "ssrc-group:%s %s"
+ },
+ { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
+ name: "msidSemantic",
+ reg: /^msid-semantic:\s?(\w*) (\S*)/,
+ names: ['semantic', 'token'],
+ format: "msid-semantic: %s %s" // space after ":" is not accidental
+ },
+ { //a=group:BUNDLE audio video
+ push: 'groups',
+ reg: /^group:(\w*) (.*)/,
+ names: ['type', 'mids'],
+ format: "group:%s %s"
+ },
+ { //a=rtcp-mux
+ name: 'rtcpMux',
+ reg: /^(rtcp-mux)/
+ },
+ { //a=rtcp-rsize
+ name: 'rtcpRsize',
+ reg: /^(rtcp-rsize)/
+ },
+ { // any a= that we don't understand is kepts verbatim on media.invalid
+ push: 'invalid',
+ names: ["value"]
+ }
+ ]
+};
+
+// set sensible defaults to avoid polluting the grammar with boring details
+Object.keys(grammar).forEach(function (key) {
+ var objs = grammar[key];
+ objs.forEach(function (obj) {
+ if (!obj.reg) {
+ obj.reg = /(.*)/;
+ }
+ if (!obj.format) {
+ obj.format = "%s";
+ }
+ });
+});
+
+},{}],72:[function(require,module,exports){
+var parser = require('./parser');
+var writer = require('./writer');
+
+exports.write = writer;
+exports.parse = parser.parse;
+exports.parseFmtpConfig = parser.parseFmtpConfig;
+exports.parsePayloads = parser.parsePayloads;
+exports.parseRemoteCandidates = parser.parseRemoteCandidates;
+
+},{"./parser":73,"./writer":74}],73:[function(require,module,exports){
+var toIntIfInt = function (v) {
+ return String(Number(v)) === v ? Number(v) : v;
+};
+
+var attachProperties = function (match, location, names, rawName) {
+ if (rawName && !names) {
+ location[rawName] = toIntIfInt(match[1]);
+ }
+ else {
+ for (var i = 0; i < names.length; i += 1) {
+ if (match[i+1] != null) {
+ location[names[i]] = toIntIfInt(match[i+1]);
+ }
+ }
+ }
+};
+
+var parseReg = function (obj, location, content) {
+ var needsBlank = obj.name && obj.names;
+ if (obj.push && !location[obj.push]) {
+ location[obj.push] = [];
+ }
+ else if (needsBlank && !location[obj.name]) {
+ location[obj.name] = {};
+ }
+ var keyLocation = obj.push ?
+ {} : // blank object that will be pushed
+ needsBlank ? location[obj.name] : location; // otherwise, named location or root
+
+ attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
+
+ if (obj.push) {
+ location[obj.push].push(keyLocation);
+ }
+};
+
+var grammar = require('./grammar');
+var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
+
+exports.parse = function (sdp) {
+ var session = {}
+ , media = []
+ , location = session; // points at where properties go under (one of the above)
+
+ // parse lines we understand
+ sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
+ var type = l[0];
+ var content = l.slice(2);
+ if (type === 'm') {
+ media.push({rtp: [], fmtp: []});
+ location = media[media.length-1]; // point at latest media line
+ }
+
+ for (var j = 0; j < (grammar[type] || []).length; j += 1) {
+ var obj = grammar[type][j];
+ if (obj.reg.test(content)) {
+ return parseReg(obj, location, content);
+ }
+ }
+ });
+
+ session.media = media; // link it up
+ return session;
+};
+
+var fmtpReducer = function (acc, expr) {
+ var s = expr.split('=');
+ if (s.length === 2) {
+ acc[s[0]] = toIntIfInt(s[1]);
+ }
+ return acc;
+};
+
+exports.parseFmtpConfig = function (str) {
+ return str.split(';').reduce(fmtpReducer, {});
+};
+
+exports.parsePayloads = function (str) {
+ return str.split(' ').map(Number);
+};
+
+exports.parseRemoteCandidates = function (str) {
+ var candidates = [];
+ var parts = str.split(' ').map(toIntIfInt);
+ for (var i = 0; i < parts.length; i += 3) {
+ candidates.push({
+ component: parts[i],
+ ip: parts[i + 1],
+ port: parts[i + 2]
+ });
+ }
+ return candidates;
+};
+
+},{"./grammar":71}],74:[function(require,module,exports){
+var grammar = require('./grammar');
+
+// customized util.format - discards excess arguments and can void middle ones
+var formatRegExp = /%[sdv%]/g;
+var format = function (formatStr) {
+ var i = 1;
+ var args = arguments;
+ var len = args.length;
+ return formatStr.replace(formatRegExp, function (x) {
+ if (i >= len) {
+ return x; // missing argument
+ }
+ var arg = args[i];
+ i += 1;
+ switch (x) {
+ case '%%':
+ return '%';
+ case '%s':
+ return String(arg);
+ case '%d':
+ return Number(arg);
+ case '%v':
+ return '';
+ }
+ });
+ // NB: we discard excess arguments - they are typically undefined from makeLine
+};
+
+var makeLine = function (type, obj, location) {
+ var str = obj.format instanceof Function ?
+ (obj.format(obj.push ? location : location[obj.name])) :
+ obj.format;
+
+ var args = [type + '=' + str];
+ if (obj.names) {
+ for (var i = 0; i < obj.names.length; i += 1) {
+ var n = obj.names[i];
+ if (obj.name) {
+ args.push(location[obj.name][n]);
+ }
+ else { // for mLine and push attributes
+ args.push(location[obj.names[i]]);
+ }
+ }
+ }
+ else {
+ args.push(location[obj.name]);
+ }
+ return format.apply(null, args);
+};
+
+// RFC specified order
+// TODO: extend this with all the rest
+var defaultOuterOrder = [
+ 'v', 'o', 's', 'i',
+ 'u', 'e', 'p', 'c',
+ 'b', 't', 'r', 'z', 'a'
+];
+var defaultInnerOrder = ['i', 'c', 'b', 'a'];
+
+
+module.exports = function (session, opts) {
+ opts = opts || {};
+ // ensure certain properties exist
+ if (session.version == null) {
+ session.version = 0; // "v=0" must be there (only defined version atm)
+ }
+ if (session.name == null) {
+ session.name = " "; // "s= " must be there if no meaningful name set
+ }
+ session.media.forEach(function (mLine) {
+ if (mLine.payloads == null) {
+ mLine.payloads = "";
+ }
+ });
+
+ var outerOrder = opts.outerOrder || defaultOuterOrder;
+ var innerOrder = opts.innerOrder || defaultInnerOrder;
+ var sdp = [];
+
+ // loop through outerOrder for matching properties on session
+ outerOrder.forEach(function (type) {
+ grammar[type].forEach(function (obj) {
+ if (obj.name in session && session[obj.name] != null) {
+ sdp.push(makeLine(type, obj, session));
+ }
+ else if (obj.push in session && session[obj.push] != null) {
+ session[obj.push].forEach(function (el) {
+ sdp.push(makeLine(type, obj, el));
+ });
+ }
+ });
+ });
+
+ // then for each media line, follow the innerOrder
+ session.media.forEach(function (mLine) {
+ sdp.push(makeLine('m', grammar.m[0], mLine));
+
+ innerOrder.forEach(function (type) {
+ grammar[type].forEach(function (obj) {
+ if (obj.name in mLine && mLine[obj.name] != null) {
+ sdp.push(makeLine(type, obj, mLine));
+ }
+ else if (obj.push in mLine && mLine[obj.push] != null) {
+ mLine[obj.push].forEach(function (el) {
+ sdp.push(makeLine(type, obj, el));
+ });
+ }
+ });
+ });
+ });
+
+ return sdp.join('\r\n') + '\r\n';
+};
+
+},{"./grammar":71}],75:[function(require,module,exports){
+var grammar = module.exports = {
+ v: [{
+ name: 'version',
+ reg: /^(\d*)$/
+ }],
+ o: [{ //o=- 20518 0 IN IP4 203.0.113.1
+ // NB: sessionId will be a String in most cases because it is huge
+ name: 'origin',
+ reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
+ names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
+ format: "%s %s %d %s IP%d %s"
+ }],
+ // default parsing of these only (though some of these feel outdated)
+ s: [{ name: 'name' }],
+ i: [{ name: 'description' }],
+ u: [{ name: 'uri' }],
+ e: [{ name: 'email' }],
+ p: [{ name: 'phone' }],
+ z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
+ r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
+ //k: [{}], // outdated thing ignored
+ t: [{ //t=0 0
+ name: 'timing',
+ reg: /^(\d*) (\d*)/,
+ names: ['start', 'stop'],
+ format: "%d %d"
+ }],
+ c: [{ //c=IN IP4 10.47.197.26
+ name: 'connection',
+ reg: /^IN IP(\d) (\S*)/,
+ names: ['version', 'ip'],
+ format: "IN IP%d %s"
+ }],
+ b: [{ //b=AS:4000
+ push: 'bandwidth',
+ reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
+ names: ['type', 'limit'],
+ format: "%s:%s"
+ }],
+ m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
+ // NB: special - pushes to session
+ // TODO: rtp/fmtp should be filtered by the payloads found here?
+ reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
+ names: ['type', 'port', 'protocol', 'payloads'],
+ format: "%s %d %s %s"
+ }],
+ a: [
+ { //a=rtpmap:110 opus/48000/2
+ push: 'rtp',
+ reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
+ names: ['payload', 'codec', 'rate', 'encoding'],
+ format: function (o) {
+ return (o.encoding) ?
+ "rtpmap:%d %s/%s/%s":
+ "rtpmap:%d %s/%s";
+ }
+ },
+ {
+ //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
+ //a=fmtp:111 minptime=10; useinbandfec=1
+ push: 'fmtp',
+ reg: /^fmtp:(\d*) ([\S| ]*)/,
+ names: ['payload', 'config'],
+ format: "fmtp:%d %s"
+ },
+ { //a=control:streamid=0
+ name: 'control',
+ reg: /^control:(.*)/,
+ format: "control:%s"
+ },
+ { //a=rtcp:65179 IN IP4 193.84.77.194
+ name: 'rtcp',
+ reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
+ names: ['port', 'netType', 'ipVer', 'address'],
+ format: function (o) {
+ return (o.address != null) ?
+ "rtcp:%d %s IP%d %s":
+ "rtcp:%d";
+ }
+ },
+ { //a=rtcp-fb:98 trr-int 100
+ push: 'rtcpFbTrrInt',
+ reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
+ names: ['payload', 'value'],
+ format: "rtcp-fb:%d trr-int %d"
+ },
+ { //a=rtcp-fb:98 nack rpsi
+ push: 'rtcpFb',
+ reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
+ names: ['payload', 'type', 'subtype'],
+ format: function (o) {
+ return (o.subtype != null) ?
+ "rtcp-fb:%s %s %s":
+ "rtcp-fb:%s %s";
+ }
+ },
+ { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+ //a=extmap:1/recvonly URI-gps-string
+ push: 'ext',
+ reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
+ names: ['value', 'uri', 'config'], // value may include "/direction" suffix
+ format: function (o) {
+ return (o.config != null) ?
+ "extmap:%s %s %s":
+ "extmap:%s %s";
+ }
+ },
+ {
+ //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
+ push: 'crypto',
+ reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
+ names: ['id', 'suite', 'config', 'sessionConfig'],
+ format: function (o) {
+ return (o.sessionConfig != null) ?
+ "crypto:%d %s %s %s":
+ "crypto:%d %s %s";
+ }
+ },
+ { //a=setup:actpass
+ name: 'setup',
+ reg: /^setup:(\w*)/,
+ format: "setup:%s"
+ },
+ { //a=mid:1
+ name: 'mid',
+ reg: /^mid:([^\s]*)/,
+ format: "mid:%s"
+ },
+ { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
+ name: 'msid',
+ reg: /^msid:(.*)/,
+ format: "msid:%s"
+ },
+ { //a=ptime:20
+ name: 'ptime',
+ reg: /^ptime:(\d*)/,
+ format: "ptime:%d"
+ },
+ { //a=maxptime:60
+ name: 'maxptime',
+ reg: /^maxptime:(\d*)/,
+ format: "maxptime:%d"
+ },
+ { //a=sendrecv
+ name: 'direction',
+ reg: /^(sendrecv|recvonly|sendonly|inactive)/
+ },
+ { //a=ice-lite
+ name: 'icelite',
+ reg: /^(ice-lite)/
+ },
+ { //a=ice-ufrag:F7gI
+ name: 'iceUfrag',
+ reg: /^ice-ufrag:(\S*)/,
+ format: "ice-ufrag:%s"
+ },
+ { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
+ name: 'icePwd',
+ reg: /^ice-pwd:(\S*)/,
+ format: "ice-pwd:%s"
+ },
+ { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
+ name: 'fingerprint',
+ reg: /^fingerprint:(\S*) (\S*)/,
+ names: ['type', 'hash'],
+ format: "fingerprint:%s %s"
+ },
+ {
+ //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
+ //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
+ //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
+ push:'candidates',
+ reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
+ names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
+ format: function (o) {
+ var str = "candidate:%s %d %s %d %s %d typ %s";
+ // NB: candidate has two optional chunks, so %void middle one if it's missing
+ str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
+ if (o.generation != null) {
+ str += " generation %d";
+ }
+ return str;
+ }
+ },
+ { //a=end-of-candidates (keep after the candidates line for readability)
+ name: 'endOfCandidates',
+ reg: /^(end-of-candidates)/
+ },
+ { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
+ name: 'remoteCandidates',
+ reg: /^remote-candidates:(.*)/,
+ format: "remote-candidates:%s"
+ },
+ { //a=ice-options:google-ice
+ name: 'iceOptions',
+ reg: /^ice-options:(\S*)/,
+ format: "ice-options:%s"
+ },
+ { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
+ push: "ssrcs",
+ reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
+ names: ['id', 'attribute', 'value'],
+ format: "ssrc:%d %s:%s"
+ },
+ { //a=ssrc-group:FEC 1 2
+ push: "ssrcGroups",
+ reg: /^ssrc-group:(\w*) (.*)/,
+ names: ['semantics', 'ssrcs'],
+ format: "ssrc-group:%s %s"
+ },
+ { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
+ name: "msidSemantic",
+ reg: /^msid-semantic:\s?(\w*) (\S*)/,
+ names: ['semantic', 'token'],
+ format: "msid-semantic: %s %s" // space after ":" is not accidental
+ },
+ { //a=group:BUNDLE audio video
+ push: 'groups',
+ reg: /^group:(\w*) (.*)/,
+ names: ['type', 'mids'],
+ format: "group:%s %s"
+ },
+ { //a=rtcp-mux
+ name: 'rtcpMux',
+ reg: /^(rtcp-mux)/
+ },
+ { //a=rtcp-rsize
+ name: 'rtcpRsize',
+ reg: /^(rtcp-rsize)/
+ },
+ { // any a= that we don't understand is kepts verbatim on media.invalid
+ push: 'invalid',
+ names: ["value"]
+ }
+ ]
+};
+
+// set sensible defaults to avoid polluting the grammar with boring details
+Object.keys(grammar).forEach(function (key) {
+ var objs = grammar[key];
+ objs.forEach(function (obj) {
+ if (!obj.reg) {
+ obj.reg = /(.*)/;
+ }
+ if (!obj.format) {
+ obj.format = "%s";
+ }
+ });
+});
+
+},{}],76:[function(require,module,exports){
arguments[4][72][0].apply(exports,arguments)
-},{"./grammar":75,"dup":72}],79:[function(require,module,exports){
+},{"./parser":77,"./writer":78,"dup":72}],77:[function(require,module,exports){
+var toIntIfInt = function (v) {
+ return String(Number(v)) === v ? Number(v) : v;
+};
+
+var attachProperties = function (match, location, names, rawName) {
+ if (rawName && !names) {
+ location[rawName] = toIntIfInt(match[1]);
+ }
+ else {
+ for (var i = 0; i < names.length; i += 1) {
+ if (match[i+1] != null) {
+ location[names[i]] = toIntIfInt(match[i+1]);
+ }
+ }
+ }
+};
+
+var parseReg = function (obj, location, content) {
+ var needsBlank = obj.name && obj.names;
+ if (obj.push && !location[obj.push]) {
+ location[obj.push] = [];
+ }
+ else if (needsBlank && !location[obj.name]) {
+ location[obj.name] = {};
+ }
+ var keyLocation = obj.push ?
+ {} : // blank object that will be pushed
+ needsBlank ? location[obj.name] : location; // otherwise, named location or root
+
+ attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
+
+ if (obj.push) {
+ location[obj.push].push(keyLocation);
+ }
+};
+
+var grammar = require('./grammar');
+var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
+
+exports.parse = function (sdp) {
+ var session = {}
+ , media = []
+ , location = session; // points at where properties go under (one of the above)
+
+ // parse lines we understand
+ sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
+ var type = l[0];
+ var content = l.slice(2);
+ if (type === 'm') {
+ media.push({rtp: [], fmtp: []});
+ location = media[media.length-1]; // point at latest media line
+ }
+
+ for (var j = 0; j < (grammar[type] || []).length; j += 1) {
+ var obj = grammar[type][j];
+ if (obj.reg.test(content)) {
+ return parseReg(obj, location, content);
+ }
+ }
+ });
+
+ session.media = media; // link it up
+ return session;
+};
+
+var fmtpReducer = function (acc, expr) {
+ var s = expr.split('=');
+ if (s.length === 2) {
+ acc[s[0]] = toIntIfInt(s[1]);
+ }
+ return acc;
+};
+
+exports.parseFmtpConfig = function (str) {
+ return str.split(/\;\s?/).reduce(fmtpReducer, {});
+};
+
+exports.parsePayloads = function (str) {
+ return str.split(' ').map(Number);
+};
+
+exports.parseRemoteCandidates = function (str) {
+ var candidates = [];
+ var parts = str.split(' ').map(toIntIfInt);
+ for (var i = 0; i < parts.length; i += 3) {
+ candidates.push({
+ component: parts[i],
+ ip: parts[i + 1],
+ port: parts[i + 2]
+ });
+ }
+ return candidates;
+};
+
+},{"./grammar":75}],78:[function(require,module,exports){
+arguments[4][74][0].apply(exports,arguments)
+},{"./grammar":75,"dup":74}],79:[function(require,module,exports){
var MediaStreamType = {
VIDEO_TYPE: "Video",
diff --git a/modules/UI/UI.js b/modules/UI/UI.js
index fcb4fae34..49a457439 100644
--- a/modules/UI/UI.js
+++ b/modules/UI/UI.js
@@ -2,7 +2,6 @@
/* jshint -W101 */
var UI = {};
-import AudioLevels from './audio_levels/AudioLevels';
import Chat from "./side_pannels/chat/Chat";
import Toolbar from "./toolbars/Toolbar";
import ToolbarToggler from "./toolbars/ToolbarToggler";
@@ -12,12 +11,12 @@ import Avatar from "./avatar/Avatar";
import PanelToggler from "./side_pannels/SidePanelToggler";
import UIUtil from "./util/UIUtil";
import UIEvents from "../../service/UI/UIEvents";
+import PreziManager from './prezi/Prezi';
+import EtherpadManager from './etherpad/Etherpad';
import VideoLayout from "./videolayout/VideoLayout";
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
-var Prezi = require("./prezi/Prezi");
-var Etherpad = require("./etherpad/Etherpad");
var EventEmitter = require("events");
var Settings = require("./../settings/Settings");
UI.messageHandler = require("./util/MessageHandler");
@@ -32,6 +31,9 @@ var Feedback = require("./Feedback");
var eventEmitter = new EventEmitter();
UI.eventEmitter = eventEmitter;
+let preziManager;
+let etherpadManager;
+
function promptDisplayName() {
let nickRequiredMsg = APP.translation.translateString("dialog.displayNameRequired");
let defaultNickMsg = APP.translation.translateString(
@@ -77,12 +79,6 @@ function promptDisplayName() {
);
}
-function setupPrezi() {
- $("#reloadPresentationLink").click(function() {
- Prezi.reloadPresentation();
- });
-}
-
function setupChat() {
Chat.init(eventEmitter);
$("#toggle_smileys").click(function() {
@@ -189,20 +185,18 @@ UI.initConference = function () {
};
function registerListeners() {
- UI.addListener(UIEvents.LARGEVIDEO_INIT, function () {
- AudioLevels.init();
- });
-
UI.addListener(UIEvents.EMAIL_CHANGED, function (email) {
UI.setUserAvatar(APP.conference.localId, email);
});
UI.addListener(UIEvents.PREZI_CLICKED, function () {
- Prezi.openPreziDialog();
+ preziManager.handlePreziButtonClicked();
});
UI.addListener(UIEvents.ETHERPAD_CLICKED, function () {
- Etherpad.toggleEtherpad(0);
+ if (etherpadManager) {
+ etherpadManager.toggleEtherpad();
+ }
});
UI.addListener(UIEvents.FULLSCREEN_TOGGLE, toggleFullScreen);
@@ -221,7 +215,7 @@ function registerListeners() {
function bindEvents() {
function onResize() {
PanelToggler.resizeChat();
- VideoLayout.resizeLargeVideoContainer();
+ VideoLayout.resizeLargeVideoContainer(PanelToggler.isVisible());
}
// Resize and reposition videos in full screen mode.
@@ -254,11 +248,17 @@ UI.start = function () {
registerListeners();
VideoLayout.init(eventEmitter);
+ if (!interfaceConfig.filmStripOnly) {
+ VideoLayout.initLargeVideo(PanelToggler.isVisible());
+ }
+ VideoLayout.resizeLargeVideoContainer(PanelToggler.isVisible());
+
ContactList.init(eventEmitter);
bindEvents();
- setupPrezi();
+ preziManager = new PreziManager(eventEmitter);
if (!interfaceConfig.filmStripOnly) {
+
$("#videospace").mousemove(function () {
return ToolbarToggler.showToolbar();
});
@@ -350,9 +350,14 @@ UI.setSubject = function (subject) {
Chat.setSubject(subject);
};
-function initEtherpad(name) {
- Etherpad.init(name);
-}
+UI.initEtherpad = function (name) {
+ if (etherpadManager) {
+ return;
+ }
+ console.log('Etherpad is enabled');
+ etherpadManager = new EtherpadManager(config.etherpad_base, name);
+ Toolbar.showEtherpadButton();
+};
UI.addUser = function (id, displayName) {
ContactList.addContact(id);
@@ -443,7 +448,6 @@ UI.getSettings = function () {
UI.toggleFilmStrip = function () {
BottomToolbar.toggleFilmStrip();
- VideoLayout.updateLargeVideoSize();
};
UI.toggleChat = function () {
@@ -592,9 +596,7 @@ UI.handleLastNEndpoints = function (ids) {
};
UI.setAudioLevel = function (id, lvl) {
- AudioLevels.updateAudioLevel(
- id, lvl, VideoLayout.getLargeVideoId()
- );
+ VideoLayout.setAudioLevel(id, lvl);
};
UI.updateDesktopSharingButtons = function () {
@@ -750,4 +752,14 @@ UI.updateAuthInfo = function (isAuthEnabled, login) {
}
};
+UI.showPrezi = function (userId, url, slide) {
+ preziManager.showPrezi(userId, url, slide);
+};
+
+UI.stopPrezi = function (userId) {
+ if (preziManager.isSharing(userId)) {
+ preziManager.removePrezi(userId);
+ }
+};
+
module.exports = UI;
diff --git a/modules/UI/audio_levels/AudioLevels.js b/modules/UI/audio_levels/AudioLevels.js
index 2e99fe94d..01a4a31ab 100644
--- a/modules/UI/audio_levels/AudioLevels.js
+++ b/modules/UI/audio_levels/AudioLevels.js
@@ -112,33 +112,6 @@ function getVideoSpanId(id) {
return videoSpanId;
}
-/**
- * Indicates that the remote video has been resized.
- */
-$(document).bind('remotevideo.resized', function (event, width, height) {
- let resized = false;
-
- $('#remoteVideos>span>canvas').each(function() {
- let canvas = $(this).get(0);
- if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
- canvas.width = width + interfaceConfig.CANVAS_EXTRA;
- resized = true;
- }
-
- if (canvas.height !== height + interfaceConfig.CANVAS_EXTRA) {
- canvas.height = height + interfaceConfig.CANVAS_EXTRA;
- resized = true;
- }
- });
-
- if (resized) {
- Object.keys(audioLevelCanvasCache).forEach(function (id) {
- audioLevelCanvasCache[id].width = width + interfaceConfig.CANVAS_EXTRA;
- audioLevelCanvasCache[id].height = height + interfaceConfig.CANVAS_EXTRA;
- });
- }
-});
-
/**
* The audio Levels plugin.
*/
@@ -248,6 +221,33 @@ const AudioLevels = {
// Fill the shape.
ASDrawContext.fill();
+ },
+
+ /**
+ * Indicates that the remote video has been resized.
+ */
+ onRemoteVideoResized (width, height) {
+ let resized = false;
+
+ $('#remoteVideos>span>canvas').each(function() {
+ let canvas = $(this).get(0);
+ if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
+ canvas.width = width + interfaceConfig.CANVAS_EXTRA;
+ resized = true;
+ }
+
+ if (canvas.height !== height + interfaceConfig.CANVAS_EXTRA) {
+ canvas.height = height + interfaceConfig.CANVAS_EXTRA;
+ resized = true;
+ }
+ });
+
+ if (resized) {
+ Object.keys(audioLevelCanvasCache).forEach(function (id) {
+ audioLevelCanvasCache[id].width = width + interfaceConfig.CANVAS_EXTRA;
+ audioLevelCanvasCache[id].height = height + interfaceConfig.CANVAS_EXTRA;
+ });
+ }
}
};
diff --git a/modules/UI/etherpad/Etherpad.js b/modules/UI/etherpad/Etherpad.js
index f0bf1cb4f..860e44615 100644
--- a/modules/UI/etherpad/Etherpad.js
+++ b/modules/UI/etherpad/Etherpad.js
@@ -1,61 +1,16 @@
-/* global $, config,
- setLargeVideoVisible, Util */
+/* global $ */
-var VideoLayout = require("../videolayout/VideoLayout");
-var Prezi = require("../prezi/Prezi");
-var UIUtil = require("../util/UIUtil");
+import VideoLayout from "../videolayout/VideoLayout";
+import LargeContainer from '../videolayout/LargeContainer';
+import UIUtil from "../util/UIUtil";
+import SidePanelToggler from "../side_pannels/SidePanelToggler";
-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 (!$('#toolbar_button_etherpad').is(":visible"))
- $('#toolbar_button_etherpad').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);
- });
-}
+const options = $.param({
+ showControns: true,
+ showChat: false,
+ showLineNumbers: true,
+ useMonospaceFont: false
+});
function bubbleIframeMouseMove(iframe){
var existingOnMouseMove = iframe.contentWindow.onmousemove;
@@ -71,8 +26,8 @@ function bubbleIframeMouseMove(iframe){
e.detail,
e.screenX,
e.screenY,
- e.clientX + boundingClientRect.left,
- e.clientY + boundingClientRect.top,
+ e.clientX + boundingClientRect.left,
+ e.clientY + boundingClientRect.top,
e.ctrlKey,
e.altKey,
e.shiftKey,
@@ -84,48 +39,123 @@ function bubbleIframeMouseMove(iframe){
};
}
+const DEFAULT_WIDTH = 640;
+const DEFAULT_HEIGHT = 480;
-var Etherpad = {
- /**
- * Initializes the etherpad.
- */
- init: function (name) {
+const EtherpadContainerType = "etherpad";
- if (config.etherpad_base && !etherpadName && name) {
+class Etherpad extends LargeContainer {
+ constructor (domain, name) {
+ super();
- domain = config.etherpad_base;
+ const iframe = document.createElement('iframe');
- etherpadName = name;
+ iframe.src = domain + name + '?' + options;
+ iframe.frameBorder = 0;
+ iframe.scrolling = "no";
+ iframe.width = DEFAULT_WIDTH;
+ iframe.height = DEFAULT_HEIGHT;
+ iframe.setAttribute('style', 'visibility: hidden;');
- enableEtherpadButton();
+ this.container.appendChild(iframe);
- /**
- * Resizes the etherpad, when the window is resized.
- */
- $(window).resize(function () {
- resize();
- });
- }
- },
+ iframe.onload = function() {
+ document.domain = document.domain;
+ bubbleIframeMouseMove(iframe);
- /**
- * Opens/hides the Etherpad.
- */
- toggleEtherpad: function (isPresentation) {
- if (!etherpadIFrame)
- createIFrame();
+ setTimeout(function() {
+ const doc = iframe.contentDocument;
+ // the iframes inside of the etherpad are
+ // not yet loaded when the etherpad iframe is loaded
+ const outer = doc.getElementsByName("ace_outer")[0];
+ bubbleIframeMouseMove(outer);
- if(VideoLayout.getLargeVideoState() === "etherpad")
- {
- VideoLayout.setLargeVideoState("video");
- }
- else
- {
- VideoLayout.setLargeVideoState("etherpad");
- }
- resize();
+ const inner = doc.getElementsByName("ace_inner")[0];
+ bubbleIframeMouseMove(inner);
+ }, 2000);
+ };
+
+ this.iframe = iframe;
}
-};
-module.exports = Etherpad;
+ get isOpen () {
+ return !!this.iframe;
+ }
+
+ get container () {
+ return document.getElementById('etherpad');
+ }
+
+ resize (containerWidth, containerHeight, animate) {
+ let remoteVideos = $('#remoteVideos');
+
+ let height = containerHeight - remoteVideos.outerHeight();
+ let width = containerWidth;
+
+ $(this.iframe).width(width).height(height);
+ }
+
+ show () {
+ const $iframe = $(this.iframe);
+ const $container = $(this.container);
+
+ return new Promise(resolve => {
+ $iframe.fadeIn(300, function () {
+ document.body.style.background = '#eeeeee';
+ $iframe.css({visibility: 'visible'});
+ $container.css({zIndex: 2});
+ resolve();
+ });
+ });
+ }
+
+ hide () {
+ const $iframe = $(this.iframe);
+ const $container = $(this.container);
+
+ return new Promise(resolve => {
+ $iframe.fadeOut(300, function () {
+ $iframe.css({visibility: 'hidden'});
+ $container.css({zIndex: 0});
+ resolve();
+ });
+ });
+ }
+}
+
+export default class EtherpadManager {
+ constructor (domain, name) {
+ if (!domain || !name) {
+ throw new Error("missing domain or name");
+ }
+
+ this.domain = domain;
+ this.name = name;
+ this.etherpad = null;
+ }
+
+ get isOpen () {
+ return !!this.etherpad;
+ }
+
+ openEtherpad () {
+ this.etherpad = new Etherpad(this.domain, this.name);
+ VideoLayout.addLargeVideoContainer(
+ EtherpadContainerType,
+ this.etherpad
+ );
+ }
+
+ toggleEtherpad () {
+ if (!this.isOpen) {
+ this.openEtherpad();
+ }
+
+ let isVisible = VideoLayout.isLargeContainerTypeVisible(
+ EtherpadContainerType
+ );
+
+ VideoLayout.showLargeVideoContainer(EtherpadContainerType, !isVisible);
+ }
+}
diff --git a/modules/UI/prezi/Prezi.js b/modules/UI/prezi/Prezi.js
index 4c2b6c61b..06ca6e24c 100644
--- a/modules/UI/prezi/Prezi.js
+++ b/modules/UI/prezi/Prezi.js
@@ -1,268 +1,21 @@
/* global $, APP */
/* jshint -W101 */
-import UIUtil from "../util/UIUtil";
+
import VideoLayout from "../videolayout/VideoLayout";
+import LargeContainer from '../videolayout/LargeContainer';
+import PreziPlayer from './PreziPlayer';
+import UIUtil from '../util/UIUtil';
+import UIEvents from '../../../service/UI/UIEvents';
+import messageHandler from '../util/MessageHandler';
+import ToolbarToggler from "../toolbars/ToolbarToggler";
+import SidePanelToggler from "../side_pannels/SidePanelToggler";
-var messageHandler = require("../util/MessageHandler");
-var PreziPlayer = require("./PreziPlayer");
+const defaultPreziLink = "http://prezi.com/wz7vhjycl7e6/my-prezi";
+const alphanumRegex = /^[a-z0-9-_\/&\?=;]+$/i;
+const aspectRatio = 16.0 / 9.0;
-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;
- }
-};
+const DEFAULT_WIDTH = 640;
+const DEFAULT_HEIGHT = 480;
/**
* Indicates if the given string is an alphanumeric string.
@@ -270,76 +23,355 @@ function presentationRemoved(event, jid, presUrl) {
* purpose of checking URIs.
*/
function isAlphanumeric(unsafeText) {
- var regex = /^[a-z0-9-_\/&\?=;]+$/i;
- return regex.test(unsafeText);
+ return alphanumRegex.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('/'));
+function getPresentationId (url) {
+ let presId = url.substring(url.indexOf("prezi.com/") + 10);
+ return presId.substring(0, presId.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);
+function isPreziLink(url) {
+ if (url.indexOf('http://prezi.com/') !== 0 && url.indexOf('https://prezi.com/') !== 0) {
+ return false;
}
- 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());
+ let presId = url.substring(url.indexOf("prezi.com/") + 10);
+ if (!isAlphanumeric(presId) || presId.indexOf('/') < 2) {
+ return false;
}
+
+ return true;
}
-/**
- * Presentation has been removed.
- */
-$(document).bind('presentationremoved.muc', presentationRemoved);
+function notifyOtherIsSharingPrezi() {
+ messageHandler.openMessageDialog(
+ "dialog.sharePreziTitle",
+ "dialog.sharePreziMsg"
+ );
+}
-/**
- * Presentation has been added.
- */
-$(document).bind('presentationadded.muc', presentationAdded);
+function proposeToClosePrezi() {
+ return new Promise(function (resolve, reject) {
+ messageHandler.openTwoButtonDialog(
+ "dialog.removePreziTitle",
+ null,
+ "dialog.removePreziMsg",
+ null,
+ false,
+ "dialog.Remove",
+ function(e,v,m,f) {
+ if (v) {
+ resolve();
+ } else {
+ reject();
+ }
+ }
+ );
-/*
- * 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);
+function requestPreziLink() {
+ const title = APP.translation.generateTranslationHTML("dialog.sharePreziTitle");
+ const cancelButton = APP.translation.generateTranslationHTML("dialog.Cancel");
+ const shareButton = APP.translation.generateTranslationHTML("dialog.Share");
+ const backButton = APP.translation.generateTranslationHTML("dialog.Back");
+ const linkError = APP.translation.generateTranslationHTML("dialog.preziLinkError");
+ const i18nOptions = {url: defaultPreziLink};
+ const defaultUrl = APP.translation.translateString(
+ "defaultPreziLink", i18nOptions
+ );
+
+ return new Promise(function (resolve, reject) {
+ let dialog = messageHandler.openDialogWithStates({
+ state0: {
+ html: `
+ ${title}
+ `,
+ persistent: false,
+ buttons: [
+ {title: cancelButton, value: false},
+ {title: shareButton, value: true}
+ ],
+ focus: ':input:first',
+ defaultButton: 1,
+ submit: function (e, v, m, f) {
+ e.preventDefault();
+ if (!v) {
+ reject('cancelled');
+ dialog.close();
+ return;
+ }
+
+ let preziUrl = f.preziUrl;
+ if (!preziUrl) {
+ return;
+ }
+
+ let urlValue = encodeURI(UIUtil.escapeHtml(preziUrl));
+
+ if (!isPreziLink(urlValue)) {
+ dialog.goToState('state1');
+ return false;
+ }
+
+ resolve(urlValue);
+ dialog.close();
+ }
+ },
+
+ state1: {
+ html: `${title}
${linkError}`,
+ persistent: false,
+ buttons: [
+ {title: cancelButton, value: false},
+ {title: backButton, value: true}
+ ],
+ focus: ':input:first',
+ defaultButton: 1,
+ submit: function (e, v, m, f) {
+ e.preventDefault();
+ if (v === 0) {
+ reject();
+ dialog.close();
+ } else {
+ dialog.goToState('state0');
+ }
+ }
+ }
+ });
+
+ });
+}
+
+export const PreziContainerType = "prezi";
+
+class PreziContainer extends LargeContainer {
+
+ constructor ({preziId, isMy, slide, onSlideChanged}) {
+ super();
+ this.reloadBtn = $('#reloadPresentation');
+
+ let preziPlayer = new PreziPlayer(
+ 'presentation', {
+ preziId,
+ width: DEFAULT_WIDTH,
+ height: DEFAULT_HEIGHT,
+ controls: isMy,
+ debug: true
+ }
+ );
+ this.preziPlayer = preziPlayer;
+ this.$iframe = $(preziPlayer.iframe);
+
+ this.$iframe.attr('id', preziId);
+
+ preziPlayer.on(PreziPlayer.EVENT_STATUS, function({value}) {
+ console.log("prezi status", value);
+ if (value == PreziPlayer.STATUS_CONTENT_READY && !isMy) {
+ preziPlayer.flyToStep(slide);
+ }
+ });
+
+ preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function({value}) {
+ console.log("event value", value);
+ onSlideChanged(value);
+ });
+ }
+
+ goToSlide (slide) {
+ if (this.preziPlayer.getCurrentStep() === slide) {
+ return;
+ }
+
+ this.preziPlayer.flyToStep(slide);
+
+ let animationStepsArray = this.preziPlayer.getAnimationCountOnSteps();
+ if (!animationStepsArray) {
+ return;
+ }
+
+ for (var i = 0; i < parseInt(animationStepsArray[slide]); i += 1) {
+ this.preziPlayer.flyToStep(slide, i);
}
}
-});
-$(window).resize(function () {
- resize();
-});
+ showReloadBtn (show) {
+ this.reloadBtn.css('display', show ? 'inline-block' : 'none');
+ }
-module.exports = Prezi;
+ show () {
+ return new Promise(resolve => {
+ this.$iframe.fadeIn(300, () => {
+ this.$iframe.css({opacity: 1});
+ ToolbarToggler.dockToolbar(true);
+ resolve();
+ });
+ });
+ }
+
+ hide () {
+ return new Promise(resolve => {
+ this.$iframe.fadeOut(300, () => {
+ this.$iframe.css({opacity: 0});
+ this.showReloadBtn(false);
+ ToolbarToggler.dockToolbar(false);
+ resolve();
+ });
+ });
+ }
+
+ onHoverIn () {
+ let rightOffset = window.innerWidth - this.$iframe.offset().left - this.$iframe.width();
+
+ this.showReloadBtn(true);
+ this.reloadBtn.css('right', rightOffset);
+ }
+
+ onHoverOut (event) {
+ let e = event.toElement || event.relatedTarget;
+
+ if (e && e.id != 'reloadPresentation' && e.id != 'header') {
+ this.showReloadBtn(false);
+ }
+ }
+
+ resize (containerWidth, containerHeight) {
+ let remoteVideos = $('#remoteVideos');
+ let height = containerHeight - remoteVideos.outerHeight();
+
+ let width = containerWidth;
+
+ if (height < width / aspectRatio) {
+ width = Math.floor(height * aspectRatio);
+ }
+
+ this.$iframe.width(width).height(height);
+ }
+
+ close () {
+ this.showReloadBtn(false);
+ this.preziPlayer.destroy();
+ this.$iframe.remove();
+ }
+}
+
+export default class PreziManager {
+ constructor (emitter) {
+ this.emitter = emitter;
+
+ this.userId = null;
+ this.url = null;
+ this.prezi = null;
+
+ $("#reloadPresentationLink").click(this.reloadPresentation.bind(this));
+ }
+
+ get isPresenting () {
+ return !!this.userId;
+ }
+
+ get isMyPrezi () {
+ return this.userId === APP.conference.localId;
+ }
+
+ isSharing (id) {
+ return this.userId === id;
+ }
+
+ handlePreziButtonClicked () {
+ if (!this.isPresenting) {
+ requestPreziLink().then(
+ url => this.emitter.emit(UIEvents.SHARE_PREZI, url, 0),
+ err => console.error('PREZI CANCELED', err)
+ );
+ return;
+ }
+
+ if (this.isMyPrezi) {
+ proposeToClosePrezi().then(() => this.emitter.emit(UIEvents.STOP_SHARING_PREZI));
+ } else {
+ notifyOtherIsSharingPrezi();
+ }
+ }
+
+ reloadPresentation () {
+ if (!this.prezi) {
+ return;
+ }
+ let iframe = this.prezi.$iframe[0];
+ iframe.src = iframe.src;
+ }
+
+ showPrezi (id, url, slide) {
+ if (!this.isPresenting) {
+ this.createPrezi(id, url, slide);
+ }
+
+ if (this.userId === id && this.url === url) {
+ this.prezi.goToSlide(slide);
+ } else {
+ console.error(this.userId, id);
+ console.error(this.url, url);
+ throw new Error("unexpected presentation change");
+ }
+ }
+
+ createPrezi (id, url, slide) {
+ console.log("presentation added", url);
+
+ this.userId = id;
+ this.url = url;
+
+ let preziId = getPresentationId(url);
+ let elementId = `participant_${id}_${preziId}`;
+
+ this.$thumb = $(VideoLayout.addRemoteVideoContainer(elementId));
+ VideoLayout.resizeThumbnails();
+ this.$thumb.css({
+ 'background-image': 'url(../images/avatarprezi.png)'
+ }).click(() => VideoLayout.showLargeVideoContainer(PreziContainerType, true));
+
+ this.prezi = new PreziContainer({
+ preziId,
+ isMy: this.isMyPrezi,
+ slide,
+ onSlideChanged: newSlide => {
+ if (this.isMyPrezi) {
+ this.emitter.emit(UIEvents.SHARE_PREZI, url, newSlide);
+ }
+ }
+ });
+
+ VideoLayout.addLargeVideoContainer(PreziContainerType, this.prezi);
+ VideoLayout.showLargeVideoContainer(PreziContainerType, true);
+ }
+
+ removePrezi (id) {
+ if (this.userId !== id) {
+ throw new Error(`cannot close presentation from ${this.userId} instead of ${id}`);
+ }
+
+ this.$thumb.remove();
+ this.$thumb = null;
+
+ // wait until Prezi is hidden, then remove it
+ VideoLayout.showLargeVideoContainer(PreziContainerType, false).then(() => {
+ console.log("presentation removed", this.url);
+
+ VideoLayout.removeLargeVideoContainer(PreziContainerType);
+
+ this.userId = null;
+ this.url = null;
+ this.prezi.close();
+ this.prezi = null;
+ });
+ }
+}
diff --git a/modules/UI/prezi/PreziPlayer.js b/modules/UI/prezi/PreziPlayer.js
index 976f1db5c..b962057ac 100644
--- a/modules/UI/prezi/PreziPlayer.js
+++ b/modules/UI/prezi/PreziPlayer.js
@@ -1,298 +1,290 @@
-/* global PreziPlayer */
/* jshint -W101 */
-(function() {
- "use strict";
- var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
- window.PreziPlayer = (function() {
+var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
- 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.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) {
- 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--) {
+PreziPlayer.prototype.changesHandler = function(message) {
+ var key, value, j, item;
+ if (this.initPollInterval) {
+ clearInterval(this.initPollInterval);
+ this.initPollInterval = false;
+ }
+ for (key in message.data) {
+ if (message.data.hasOwnProperty(key)){
+ value = message.data[key];
+ this.values[key] = value;
+ for (j=0; j 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) {
+ 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);
+}
+
+window.PreziPlayer = PreziPlayer;
+
+export default PreziPlayer;
diff --git a/modules/UI/side_pannels/SidePanelToggler.js b/modules/UI/side_pannels/SidePanelToggler.js
index 07a39e561..f3742a2cd 100644
--- a/modules/UI/side_pannels/SidePanelToggler.js
+++ b/modules/UI/side_pannels/SidePanelToggler.js
@@ -6,7 +6,6 @@ import SettingsMenu from "./settings/SettingsMenu";
import VideoLayout from "../videolayout/VideoLayout";
import ToolbarToggler from "../toolbars/ToolbarToggler";
import UIUtil from "../util/UIUtil";
-import LargeVideo from "../videolayout/LargeVideo";
const buttons = {
'#chatspace': '#chatBottomButton',
@@ -47,7 +46,7 @@ function toggle (object, selector, onOpenComplete, onOpen, onClose) {
} else {
// Undock the toolbar when the chat is shown and if we're in a
// video mode.
- if (LargeVideo.isLargeVideoVisible()) {
+ if (VideoLayout.isLargeVideoVisible()) {
ToolbarToggler.dockToolbar(false);
}
@@ -62,7 +61,7 @@ function toggle (object, selector, onOpenComplete, onOpen, onClose) {
}
$("#toast-container").animate({
- right: (PanelToggler.getPanelSize()[0] + 5)
+ right: (UIUtil.getSidePanelSize()[0] + 5)
}, {
queue: false,
duration: 500
@@ -116,7 +115,7 @@ var PanelToggler = {
},
resizeChat () {
- let [width, height] = this.getPanelSize();
+ let [width, height] = UIUtil.getSidePanelSize();
Chat.resizeChat(width, height);
},
@@ -156,21 +155,6 @@ var PanelToggler = {
null);
},
- /**
- * Returns the size of the side panel.
- */
- getPanelSize () {
- var availableHeight = window.innerHeight;
- var availableWidth = window.innerWidth;
-
- var panelWidth = 200;
- if (availableWidth * 0.2 < 200) {
- panelWidth = availableWidth * 0.2;
- }
-
- return [panelWidth, availableHeight];
- },
-
isVisible () {
return (Chat.isVisible() ||
ContactList.isVisible() ||
diff --git a/modules/UI/toolbars/BottomToolbar.js b/modules/UI/toolbars/BottomToolbar.js
index a937c3fbf..6d9ca1554 100644
--- a/modules/UI/toolbars/BottomToolbar.js
+++ b/modules/UI/toolbars/BottomToolbar.js
@@ -9,13 +9,6 @@ const defaultBottomToolbarButtons = {
'filmstrip': '#bottom_toolbar_film_strip'
};
-$(document).bind("remotevideo.resized", function (event, width, height) {
- let toolbar = $('#bottomToolbar');
- let bottom = (height - toolbar.outerHeight())/2 + 18;
-
- toolbar.css({bottom});
-});
-
const BottomToolbar = {
init (emitter) {
UIUtil.hideDisabledButtons(defaultBottomToolbarButtons);
@@ -42,6 +35,13 @@ const BottomToolbar = {
toggleFilmStrip () {
$("#remoteVideos").toggleClass("hidden");
+ },
+
+ onRemoteVideoResized (width, height) {
+ let toolbar = $('#bottomToolbar');
+ let bottom = (height - toolbar.outerHeight())/2 + 18;
+
+ toolbar.css({bottom});
}
};
diff --git a/modules/UI/toolbars/Toolbar.js b/modules/UI/toolbars/Toolbar.js
index ee43423ad..730195ce1 100644
--- a/modules/UI/toolbars/Toolbar.js
+++ b/modules/UI/toolbars/Toolbar.js
@@ -182,17 +182,17 @@ const buttonHandlers = {
}
};
const defaultToolbarButtons = {
- 'microphone': '#toolbar_button_mute',
- 'camera': '#toolbar_button_camera',
- 'desktop': '#toolbar_button_desktopsharing',
- 'security': '#toolbar_button_security',
- 'invite': '#toolbar_button_link',
- 'chat': '#toolbar_button_chat',
- 'prezi': '#toolbar_button_prezi',
- 'etherpad': '#toolbar_button_etherpad',
- 'fullscreen': '#toolbar_button_fullScreen',
- 'settings': '#toolbar_button_settings',
- 'hangup': '#toolbar_button_hangup'
+ 'microphone': '#toolbar_button_mute',
+ 'camera': '#toolbar_button_camera',
+ 'desktop': '#toolbar_button_desktopsharing',
+ 'security': '#toolbar_button_security',
+ 'invite': '#toolbar_button_link',
+ 'chat': '#toolbar_button_chat',
+ 'prezi': '#toolbar_button_prezi',
+ 'etherpad': '#toolbar_button_etherpad',
+ 'fullscreen': '#toolbar_button_fullScreen',
+ 'settings': '#toolbar_button_settings',
+ 'hangup': '#toolbar_button_hangup'
};
function dialpadButtonClicked() {
@@ -208,7 +208,7 @@ function showSipNumberInput () {
messageHandler.openTwoButtonDialog(
null, null, null,
`${sipMsg}
- `,
+ `,
false, "dialog.Dial",
function (e, v, m, f) {
if (v && f.sipNumber) {
@@ -250,7 +250,7 @@ const Toolbar = {
* Disables and enables some of the buttons.
*/
setupButtonsFromConfig () {
- if (UIUtil.isButtonEnabled('prezi')) {
+ if (!UIUtil.isButtonEnabled('prezi')) {
$("#toolbar_button_prezi").css({display: "none"});
}
},
@@ -283,6 +283,12 @@ const Toolbar = {
}
},
+ showEtherpadButton () {
+ if (!$('#toolbar_button_etherpad').is(":visible")) {
+ $('#toolbar_button_etherpad').css({display: 'inline-block'});
+ }
+ },
+
// Shows or hides the 'recording' button.
showRecordingButton (show) {
if (UIUtil.isButtonEnabled('recording') && show) {
@@ -304,7 +310,7 @@ const Toolbar = {
// we have params to start automatically sharing
checkAutoEnableDesktopSharing () {
if (UIUtil.isButtonEnabled('desktop')
- && config.autoEnableDesktopSharing) {
+ && config.autoEnableDesktopSharing) {
APP.desktopsharing.toggleScreenSharing();
}
},
diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js
index d1dc7a21c..2a1f084a0 100644
--- a/modules/UI/util/UIUtil.js
+++ b/modules/UI/util/UIUtil.js
@@ -1,19 +1,34 @@
/* global $, config, interfaceConfig */
-import PanelToggler from "../side_pannels/SidePanelToggler";
-
/**
* Created by hristo on 12/22/14.
*/
var UIUtil = {
+
+ /**
+ * Returns the size of the side panel.
+ */
+ getSidePanelSize () {
+ var availableHeight = window.innerHeight;
+ var availableWidth = window.innerWidth;
+
+ var panelWidth = 200;
+ if (availableWidth * 0.2 < 200) {
+ panelWidth = availableWidth * 0.2;
+ }
+
+ return [panelWidth, availableHeight];
+ },
+
/**
* Returns the available video width.
*/
- getAvailableVideoWidth: function (isVisible) {
- if(typeof isVisible === "undefined" || isVisible === null)
- isVisible = PanelToggler.isVisible();
- var rightPanelWidth
- = isVisible ? PanelToggler.getPanelSize()[0] : 0;
+ getAvailableVideoWidth: function (isSidePanelVisible) {
+ let rightPanelWidth = 0;
+
+ if (isSidePanelVisible) {
+ rightPanelWidth = UIUtil.getSidePanelSize()[0];
+ }
return window.innerWidth - rightPanelWidth;
},
@@ -118,6 +133,12 @@ import PanelToggler from "../side_pannels/SidePanelToggler";
redirect (url) {
window.location.href = url;
+ },
+
+ isFullScreen () {
+ return document.fullScreen
+ || document.mozFullScreen
+ || document.webkitIsFullScreen;
}
};
diff --git a/modules/UI/videolayout/LargeContainer.js b/modules/UI/videolayout/LargeContainer.js
new file mode 100644
index 000000000..b74ac50a4
--- /dev/null
+++ b/modules/UI/videolayout/LargeContainer.js
@@ -0,0 +1,24 @@
+
+export default class LargeContainer {
+
+ /**
+ * @returns Promise
+ */
+ show () {
+ }
+
+ /**
+ * @returns Promise
+ */
+ hide () {
+ }
+
+ resize (containerWidth, containerHeight, animate) {
+ }
+
+ onHoverIn (e) {
+ }
+
+ onHoverOut (e) {
+ }
+}
diff --git a/modules/UI/videolayout/LargeVideo.js b/modules/UI/videolayout/LargeVideo.js
index 921398770..dd358411c 100644
--- a/modules/UI/videolayout/LargeVideo.js
+++ b/modules/UI/videolayout/LargeVideo.js
@@ -1,98 +1,20 @@
/* global $, APP, interfaceConfig */
/* jshint -W101 */
-import Avatar from "../avatar/Avatar";
-import ToolbarToggler from "../toolbars/ToolbarToggler";
+
import UIUtil from "../util/UIUtil";
import UIEvents from "../../../service/UI/UIEvents";
+import LargeContainer from './LargeContainer';
-var RTCBrowserType = require("../../RTC/RTCBrowserType");
+const RTCBrowserType = require("../../RTC/RTCBrowserType");
-// FIXME: With Temasys we have to re-select everytime
-//var video = $('#largeVideo');
+const avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE;
-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 = "#largeVideoWrapper";
- break;
- case "etherpad":
- selector = "#etherpad>iframe";
- break;
- case "prezi":
- selector = "#presentation>iframe";
- break;
- default:
- return null;
- }
- return $(selector);
-}
-
-/**
- * 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
- });
+function getStreamId(stream) {
+ if (stream.isLocal()) {
+ return APP.conference.localId;
} else {
- video.width(width);
- video.height(height);
- video.css({
- top: verticalIndent,
- bottom: verticalIndent,
- left: horizontalIndent,
- right: horizontalIndent
- });
+ return stream.getParticipantId();
}
-
}
/**
@@ -106,80 +28,28 @@ function getDesktopVideoSize(videoWidth,
videoHeight,
videoSpaceWidth,
videoSpaceHeight) {
- if (!videoWidth)
- videoWidth = currentVideoWidth;
- if (!videoHeight)
- videoHeight = currentVideoHeight;
- var aspectRatio = videoWidth / videoHeight;
+ let aspectRatio = videoWidth / videoHeight;
- var availableWidth = Math.max(videoWidth, videoSpaceWidth);
- var availableHeight = Math.max(videoHeight, videoSpaceHeight);
+ let availableWidth = Math.max(videoWidth, videoSpaceWidth);
+ let availableHeight = Math.max(videoHeight, videoSpaceHeight);
- var filmstrip = $("#remoteVideos");
+ let filmstrip = $("#remoteVideos");
if (!filmstrip.hasClass("hidden"))
videoSpaceHeight -= filmstrip.outerHeight();
- if (availableWidth / aspectRatio >= videoSpaceHeight)
- {
+ if (availableWidth / aspectRatio >= videoSpaceHeight) {
availableHeight = videoSpaceHeight;
availableWidth = availableHeight * aspectRatio;
}
- if (availableHeight * aspectRatio >= videoSpaceWidth)
- {
+ 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];
+ return { availableWidth, availableHeight };
}
@@ -199,15 +69,10 @@ function getCameraVideoSize(videoWidth,
videoSpaceWidth,
videoSpaceHeight) {
- if (!videoWidth)
- videoWidth = currentVideoWidth;
- if (!videoHeight)
- videoHeight = currentVideoHeight;
+ let aspectRatio = videoWidth / videoHeight;
- var aspectRatio = videoWidth / videoHeight;
-
- var availableWidth = videoWidth;
- var availableHeight = videoHeight;
+ let availableWidth = videoWidth;
+ let availableHeight = videoHeight;
if (interfaceConfig.VIDEO_LAYOUT_FIT == 'height') {
availableHeight = videoSpaceHeight;
@@ -233,487 +98,341 @@ function getCameraVideoSize(videoWidth,
}
- return [availableWidth, availableHeight];
+ return { availableWidth, availableHeight };
}
/**
- * Updates the src of the active speaker avatar
+ * 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 updateActiveSpeakerAvatarSrc() {
- let avatar = $("#activeSpeakerAvatar");
- let id = currentSmallVideo.id;
- let url = Avatar.getActiveSpeakerUrl(id);
- if (id && avatar.attr('src') !== url) {
- avatar.attr('src', url);
- currentSmallVideo.showAvatar();
+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.
+ if (UIUtil.isFullScreen()) {
+ videoSpaceHeight = window.innerHeight;
}
+
+ let horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
+ let verticalIndent = (videoSpaceHeight - videoHeight) / 2;
+
+ return { horizontalIndent, verticalIndent };
}
/**
- * Change the video source of the large video.
- * @param isVisible
+ * 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 changeVideo(isVisible) {
+function getDesktopVideoPosition(videoWidth,
+ videoHeight,
+ videoSpaceWidth,
+ videoSpaceHeight) {
- if (!currentSmallVideo) {
- console.error("Unable to change large video - no 'currentSmallVideo'");
- return;
- }
+ let horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
- updateActiveSpeakerAvatarSrc();
- let largeVideoElement = $('#largeVideo');
+ let verticalIndent = 0;// Top aligned
- currentSmallVideo.stream.attach(largeVideoElement);
-
- let flipX = currentSmallVideo.flipX;
-
- largeVideoElement.css({
- transform: flipX ? "scaleX(-1)" : "none"
- });
-
- LargeVideo.updateVideoSizeAndPosition(currentSmallVideo.getVideoType());
-
- // Only if the large video is currently visible.
- if (isVisible) {
- LargeVideo.VideoLayout.largeVideoUpdated(currentSmallVideo);
-
- $('#largeVideoWrapper').fadeTo(300, 1);
- }
+ return { horizontalIndent, verticalIndent };
}
-/**
- * Creates the html elements for the large video.
- */
-function createLargeVideoHTML()
-{
- var html = '';
- html += '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- ' jitsi.org' +
- ''+
- '
' +
- '
![]()
' +
- '
' +
- '
' +
- '
' +
- '' +
- '
' +
- '
';
- html += '
';
- $(html).prependTo("#videospace");
+export const VideoContainerType = "video";
- 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;
+class VideoContainer extends LargeContainer {
+ // FIXME: With Temasys we have to re-select everytime
+ get $video () {
+ return $('#largeVideo');
}
- 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)";
+ get id () {
+ if (this.stream) {
+ return getStreamId(this.stream);
+ }
}
- if (interfaceConfig.SHOW_POWERED_BY) {
- $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
+ constructor (onPlay) {
+ super();
+ this.stream = null;
+
+ this.$avatar = $('#activeSpeaker');
+ this.$wrapper = $('#largeVideoWrapper');
+
+ if (!RTCBrowserType.isIExplorer()) {
+ this.$video.volume = 0;
+ }
+
+ this.$video.on('play', onPlay);
}
- 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);
+ getStreamSize () {
+ let video = this.$video[0];
+ return {
+ width: video.videoWidth,
+ height: video.videoHeight
};
- largeVideo.onplaying = onplaying;
- },
- /**
- * Indicates if the large video is currently visible.
- *
- * @return true if visible, false - otherwise
- */
- isLargeVideoVisible: function() {
- return $('#largeVideoWrapper').is(':visible');
- },
- /**
- * Returns true if the user is currently displayed on large video.
- */
- isCurrentlyOnLarge: function (id) {
- return id && id === this.getId();
- },
- /**
- * Updates the large video with the given new video source.
- */
- updateLargeVideo: function (id, forceUpdate) {
- if(!isEnabled) {
- return;
- }
- let newSmallVideo = this.VideoLayout.getSmallVideo(id);
- console.info(`hover in ${id} , video: `, newSmallVideo);
+ }
- if (!newSmallVideo) {
- console.error("Small video not found for: " + id);
- return;
- }
-
- if (!LargeVideo.isCurrentlyOnLarge(id) || forceUpdate) {
- $('#activeSpeaker').css('visibility', 'hidden');
-
- let oldId = this.getId();
-
- currentSmallVideo = newSmallVideo;
-
- if (oldId !== id) {
- // we want the notification to trigger even if id is undefined,
- // or null.
- this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
- }
- // We are doing fadeOut/fadeIn animations on parent div which wraps
- // largeVideo, because when Temasys plugin is in use it replaces
- //