Commit 54a2e2d3 authored by daryl herzmann's avatar daryl herzmann

Merge pull request #131 from deleolajide/version-0.0.3

Open Meetings Plugin version 0.0.3
parents 5c389be0 347a55dc
...@@ -49,6 +49,16 @@ ...@@ -49,6 +49,16 @@
Openfire Meetings Plugin Changelog Openfire Meetings Plugin Changelog
</h1> </h1>
<p><b>0.0.3</b> -- Dec 6th, 2014</p>
<ul>
<li>Changed version to 3.9.9 to overcome bug in openfire version control</li>
<li>Added recording parameters to admin web page</li>
<li>Updated Jitsi Meet and Jitsi Videobridge</li>
<li>Added Spark plugin</li>
<li>Added support for Openfire vCard avatars</li>
</ul>
<p><b>0.0.2</b> -- Nov 30th, 2014</p> <p><b>0.0.2</b> -- Nov 30th, 2014</p>
<ul> <ul>
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
<name>ofmeet</name> <name>ofmeet</name>
<description>Openfire Meetings</description> <description>Openfire Meetings</description>
<author></author> <author></author>
<version>0.0.2</version> <version>0.0.3</version>
<date>11/30/2014</date> <date>11/30/2014</date>
<minServerVersion>3.9.4</minServerVersion> <minServerVersion>3.9.9</minServerVersion>
<adminconsole> <adminconsole>
<tab id="tab-ofmeet" name="${plugin.title}" url="ofmeet-summary.jsp" description="${plugin.description}"> <tab id="tab-ofmeet" name="${plugin.title}" url="ofmeet-summary.jsp" description="${plugin.description}">
......
...@@ -54,8 +54,29 @@ ...@@ -54,8 +54,29 @@
Openfire Meetings Openfire Meetings
</p> </p>
<h2>Installation</h2>
<div>
<p>Ignite Realtime is pleased to announce "Openfire Meeting", a new plugin for Openfire that continues the development of the ofmeet web application which was part of the deprecated <a href="https://community.igniterealtime.org/community/support/jitsi_videobridge_plugin">Jitsi-videobridge plugin</a>.</p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><strong>PLEASE NOTE</strong> - You will need latest Openfire 3.10.0 to use this plugin. Use a nightly build or wait for the imminent official release.</p>
<p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22181/ofmeet1.png"><img alt="ofmeet1.png" height="272" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22181/432-272/ofmeet1.png" style="width:432px; height: 272.438709677419px;" width="432"/></a></p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p>Openfire Meetings is a complete standalone plugin powered by Jitsi Videobridge. It does not depend on any other plugins</p><p style="min-height: 8pt; padding: 0px;">&nbsp;</p>
<p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22275/ofmeet3.png"><img alt="ofmeet3.png" height="160" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22275/428-160/ofmeet3.png" style="width:428px; height: 160.325732899023px;" width="428"/></a></p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p>The front-end we application is a combination of Candy and Jitsi Meet and enables the following features</p>
<ul>
<li>Openfire user authentication directly from web browser for both Candy and Jitsi Meet</li>
<li>Audio, Video and Telephone (SIP) conferencing directly with Jitsi Meet and from Candy</li>
<li>Desktop sharing (screen and applications) using the Openfire Meeting Chrome extension</li>
<li>Fastpath user agent with audio and video using the Candy and Jitsi Meet web applications. It also requires Fastpath plugin to be installed.</li>
<li>Configuration directly from Openfire admin web pages.</li>
</ul>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22276/ofmeet2.png"><img alt="ofmeet2.png" height="224" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22276/397-224/ofmeet2.png" style="width:397px; height: 223.661971830986px;" width="397"/></a></p>
<p><strong>How to use</strong></p>
<p><span>Jitsi Meet - </span>https://your-server.com:7443/ofmeet</p>
<p><span>Spark Plugin - </span>https://your-server.com:7443/ofmeet/spark/ofmeet-plugin.jar</p>
<p>Candy - https://your-server.com:7443/ofmeet/candy.html</p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22278/ofmeet5.png"><img alt="ofmeet5.png" height="93" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22278/ofmeet5.png" style="height: auto;" width="300"/></a></p>
<p>Discussion place is in the <a href="https://community.igniterealtime.org/community/plugins/commplugins/openfire-meetings/activity">community plugins, here</a></p>
</div>
</body> </body>
</html> </html>
...@@ -11,8 +11,12 @@ var recordingToken =''; ...@@ -11,8 +11,12 @@ var recordingToken ='';
var roomUrl = null; var roomUrl = null;
var roomName = null; var roomName = null;
var ssrc2jid = {}; var ssrc2jid = {};
var mediaStreams = []; var mediaStreams = {};
var bridgeIsDown = false; var bridgeIsDown = false;
//TODO: this array must be removed when firefox implement multistream support
var notReceivedSSRCs = [];
var jid2Ssrc = {};
/** /**
* The stats collector that process stats data and triggers updates to app.js. * The stats collector that process stats data and triggers updates to app.js.
...@@ -31,7 +35,6 @@ var localStatsCollector = null; ...@@ -31,7 +35,6 @@ var localStatsCollector = null;
* FIXME: remove those maps * FIXME: remove those maps
*/ */
var ssrc2videoType = {}; var ssrc2videoType = {};
var videoSrcToSsrc = {};
/** /**
* Currently focused video "src"(displayed in large video). * Currently focused video "src"(displayed in large video).
* @type {String} * @type {String}
...@@ -65,26 +68,43 @@ function init() { ...@@ -65,26 +68,43 @@ function init() {
if (RTC === null) { if (RTC === null) {
window.location.href = 'webrtcrequired.html'; window.location.href = 'webrtcrequired.html';
return; return;
} else if (RTC.browser !== 'chrome') { } else if (RTC.browser !== 'chrome' &&
config.enableFirefoxSupport !== true) {
window.location.href = 'chromeonly.html'; window.location.href = 'chromeonly.html';
return; return;
} }
obtainAudioAndVideoPermissions(function (stream) { obtainAudioAndVideoPermissions(function (stream) {
var audioStream = new webkitMediaStream(); var audioStream, videoStream;
var videoStream = new webkitMediaStream(); if(window.webkitMediaStream)
var audioTracks = stream.getAudioTracks(); {
var videoTracks = stream.getVideoTracks(); var audioStream = new webkitMediaStream();
for (var i = 0; i < audioTracks.length; i++) { var videoStream = new webkitMediaStream();
audioStream.addTrack(audioTracks[i]); var audioTracks = stream.getAudioTracks();
var videoTracks = stream.getVideoTracks();
for (var i = 0; i < audioTracks.length; i++) {
audioStream.addTrack(audioTracks[i]);
}
for (i = 0; i < videoTracks.length; i++) {
videoStream.addTrack(videoTracks[i]);
}
VideoLayout.changeLocalAudio(audioStream);
startLocalRtpStatsCollector(audioStream);
VideoLayout.changeLocalVideo(videoStream, true);
} }
VideoLayout.changeLocalAudio(audioStream); else
startLocalRtpStatsCollector(audioStream); {
VideoLayout.changeLocalStream(stream);
startLocalRtpStatsCollector(stream);
for (i = 0; i < videoTracks.length; i++) {
videoStream.addTrack(videoTracks[i]);
} }
VideoLayout.changeLocalVideo(videoStream, true);
maybeDoJoin(); maybeDoJoin();
}); });
...@@ -106,13 +126,20 @@ function connect(jid, password) { ...@@ -106,13 +126,20 @@ function connect(jid, password) {
localAudio = connection.jingle.localAudio; localAudio = connection.jingle.localAudio;
localVideo = connection.jingle.localVideo; localVideo = connection.jingle.localVideo;
} }
// BAO // BAO
connection = new Openfire.Connection(document.getElementById('boshURL').value || config.bosh || '/http-bind'); connection = new Openfire.Connection(document.getElementById('boshURL').value || config.bosh || '/http-bind');
//connection.rawInput = function (data) { console.log('RECV: ' + data); };
//connection.rawOutput = function (data) { console.log('SEND: ' + data); }; var email = SettingsMenu.getEmail();
var displayName = SettingsMenu.getDisplayName();
if (nickname) { if(email) {
connection.emuc.addDisplayNameToPresence(nickname); connection.emuc.addEmailToPresence(email);
} else {
connection.emuc.addUserIdToPresence(SettingsMenu.getUID());
}
if(displayName) {
connection.emuc.addDisplayNameToPresence(displayName);
} }
if (connection.disco) { if (connection.disco) {
...@@ -167,24 +194,33 @@ function connect(jid, password) { ...@@ -167,24 +194,33 @@ function connect(jid, password) {
*/ */
function obtainAudioAndVideoPermissions(callback) { function obtainAudioAndVideoPermissions(callback) {
// Get AV // Get AV
var cb = function (stream) {
console.log('got', stream, stream.getAudioTracks().length, stream.getVideoTracks().length);
callback(stream);
trackUsage('localMedia', {
audio: stream.getAudioTracks().length,
video: stream.getVideoTracks().length
});
}
getUserMediaWithConstraints( getUserMediaWithConstraints(
['audio', 'video'], ['audio', 'video'],
function (avStream) { cb,
callback(avStream);
trackUsage('localMedia', {
audio: avStream.getAudioTracks().length,
video: avStream.getVideoTracks().length
});
},
function (error) { function (error) {
console.error('failed to obtain audio/video stream - stop', error); console.error('failed to obtain audio/video stream - trying audio only', error);
trackUsage('localMediaError', { getUserMediaWithConstraints(
media: error.media || 'video', ['audio'],
name : error.name cb,
}); function (error) {
messageHandler.showError("Error", console.error('failed to obtain audio/video stream - stop', error);
"Failed to obtain permissions to use the local microphone" + trackUsage('localMediaError', {
"and/or camera."); media: error.media || 'video',
name : error.name
});
messageHandler.showError("Error",
"Failed to obtain permissions to use the local microphone" +
"and/or camera.");
}
);
}, },
config.resolution || '360'); config.resolution || '360');
} }
...@@ -247,11 +283,11 @@ function doJoin() { ...@@ -247,11 +283,11 @@ function doJoin() {
roomjid += '/' + tmpJid; roomjid += '/' + tmpJid;
} }
connection.ofmuc.roomJid = roomName; // BAO
connection.emuc.doJoin(roomjid); connection.emuc.doJoin(roomjid);
} }
function waitForRemoteVideo(selector, ssrc, stream) { function waitForRemoteVideo(selector, ssrc, stream, jid) {
// XXX(gp) so, every call to this function is *always* preceded by a call // XXX(gp) so, every call to this function is *always* preceded by a call
// to the RTC.attachMediaStream() function but that call is *not* followed // to the RTC.attachMediaStream() function but that call is *not* followed
// by an update to the videoSrcToSsrc map! // by an update to the videoSrcToSsrc map!
...@@ -283,17 +319,17 @@ function waitForRemoteVideo(selector, ssrc, stream) { ...@@ -283,17 +319,17 @@ function waitForRemoteVideo(selector, ssrc, stream) {
// FIXME: add a class that will associate peer Jid, video.src, it's ssrc and video type // FIXME: add a class that will associate peer Jid, video.src, it's ssrc and video type
// in order to get rid of too many maps // in order to get rid of too many maps
if (ssrc && selector.attr('src')) { if (ssrc && jid) {
videoSrcToSsrc[selector.attr('src')] = ssrc; jid2Ssrc[Strophe.getResourceFromJid(jid)] = ssrc;
} else { } else {
console.warn("No ssrc given for video", selector); console.warn("No ssrc given for jid", jid);
messageHandler.showError('Warning', 'No ssrc was given for the video.'); // messageHandler.showError('Warning', 'No ssrc was given for the video.');
} }
$(document).trigger('videoactive.jingle', [selector]); $(document).trigger('videoactive.jingle', [selector]);
} else { } else {
setTimeout(function () { setTimeout(function () {
waitForRemoteVideo(selector, ssrc, stream); waitForRemoteVideo(selector, ssrc, stream, jid);
}, 250); }, 250);
} }
} }
...@@ -306,16 +342,19 @@ function waitForPresence(data, sid) { ...@@ -306,16 +342,19 @@ function waitForPresence(data, sid) {
var sess = connection.jingle.sessions[sid]; var sess = connection.jingle.sessions[sid];
var thessrc; var thessrc;
// look up an associated JID for a stream id // look up an associated JID for a stream id
if (data.stream.id.indexOf('mixedmslabel') === -1) { if (data.stream.id && data.stream.id.indexOf('mixedmslabel') === -1) {
// look only at a=ssrc: and _not_ at a=ssrc-group: lines // look only at a=ssrc: and _not_ at a=ssrc-group: lines
var ssrclines var ssrclines
= SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc:'); = SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc:');
ssrclines = ssrclines.filter(function (line) { ssrclines = ssrclines.filter(function (line) {
// NOTE(gp) previously we filtered on the mslabel, but that property // NOTE(gp) previously we filtered on the mslabel, but that property
// is not always present. // is not always present.
// return line.indexOf('mslabel:' + data.stream.label) !== -1; // return line.indexOf('mslabel:' + data.stream.label) !== -1;
return line.indexOf('msid:' + data.stream.id) !== -1;
return ((line.indexOf('msid:' + data.stream.id) !== -1));
}); });
if (ssrclines.length) { if (ssrclines.length) {
thessrc = ssrclines[0].substring(7).split(' ')[0]; thessrc = ssrclines[0].substring(7).split(' ')[0];
...@@ -345,10 +384,36 @@ function waitForPresence(data, sid) { ...@@ -345,10 +384,36 @@ function waitForPresence(data, sid) {
} }
} }
//TODO: this code should be removed when firefox implement multistream support
if(RTC.browser == "firefox")
{
if((notReceivedSSRCs.length == 0) ||
!ssrc2jid[notReceivedSSRCs[notReceivedSSRCs.length - 1]])
{
// TODO(gp) limit wait duration to 1 sec.
setTimeout(function(d, s) {
return function() {
waitForPresence(d, s);
}
}(data, sid), 250);
return;
}
thessrc = notReceivedSSRCs.pop();
if (ssrc2jid[thessrc]) {
data.peerjid = ssrc2jid[thessrc];
}
}
// NOTE(gp) now that we have simulcast, a media stream can have more than 1 // NOTE(gp) now that we have simulcast, a media stream can have more than 1
// ssrc. We should probably take that into account in our MediaStream // ssrc. We should probably take that into account in our MediaStream
// wrapper. // wrapper.
mediaStreams.push(new MediaStream(data, sid, thessrc)); var mediaStream = new MediaStream(data, sid, thessrc);
var jid = data.peerjid || connection.emuc.myroomjid;
if(!mediaStreams[jid]) {
mediaStreams[jid] = {};
}
mediaStreams[jid][mediaStream.type] = mediaStream;
var container; var container;
var remotes = document.getElementById('remoteVideos'); var remotes = document.getElementById('remoteVideos');
...@@ -396,25 +461,6 @@ function waitForPresence(data, sid) { ...@@ -396,25 +461,6 @@ function waitForPresence(data, sid) {
} }
} }
/**
* Returns the JID of the user to whom given <tt>videoSrc</tt> belongs.
* @param videoSrc the video "src" identifier.
* @returns {null | String} the JID of the user to whom given <tt>videoSrc</tt>
* belongs.
*/
function getJidFromVideoSrc(videoSrc)
{
if (videoSrc === localVideoSrc)
return connection.emuc.myroomjid;
var ssrc = videoSrcToSsrc[videoSrc];
if (!ssrc)
{
return null;
}
return ssrc2jid[ssrc];
}
// an attempt to work around https://github.com/jitsi/jitmeet/issues/32 // an attempt to work around https://github.com/jitsi/jitmeet/issues/32
function sendKeyframe(pc) { function sendKeyframe(pc) {
console.log('sendkeyframe', pc.iceConnectionState); console.log('sendkeyframe', pc.iceConnectionState);
...@@ -623,15 +669,27 @@ $(document).bind('setLocalDescription.jingle', function (event, sid) { ...@@ -623,15 +669,27 @@ $(document).bind('setLocalDescription.jingle', function (event, sid) {
var media = simulcast.parseMedia(sess.peerconnection.localDescription); var media = simulcast.parseMedia(sess.peerconnection.localDescription);
media.forEach(function (media) { media.forEach(function (media) {
// TODO(gp) maybe exclude FID streams? if(Object.keys(media.sources).length > 0) {
Object.keys(media.sources).forEach(function(ssrc) { // TODO(gp) maybe exclude FID streams?
Object.keys(media.sources).forEach(function (ssrc) {
newssrcs.push({
'ssrc': ssrc,
'type': media.type,
'direction': media.direction
});
});
}
else if(sess.localStreamsSSRC && sess.localStreamsSSRC[media.type])
{
newssrcs.push({ newssrcs.push({
'ssrc': ssrc, 'ssrc': sess.localStreamsSSRC[media.type],
'type': media.type, 'type': media.type,
'direction': media.direction 'direction': media.direction
}); });
}); }
}); });
console.log('new ssrcs', newssrcs); console.log('new ssrcs', newssrcs);
// Have to clear presence map to get rid of removed streams // Have to clear presence map to get rid of removed streams
...@@ -664,20 +722,22 @@ $(document).bind('iceconnectionstatechange.jingle', function (event, sid, sessio ...@@ -664,20 +722,22 @@ $(document).bind('iceconnectionstatechange.jingle', function (event, sid, sessio
var metadata = {}; var metadata = {};
metadata.setupTime = (new Date()).getTime() - session.timeChecking; metadata.setupTime = (new Date()).getTime() - session.timeChecking;
session.peerconnection.getStats(function (res) { session.peerconnection.getStats(function (res) {
res.result().forEach(function (report) { if(res && res.result) {
if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') { res.result().forEach(function (report) {
metadata.localCandidateType = report.stat('googLocalCandidateType'); if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') {
metadata.remoteCandidateType = report.stat('googRemoteCandidateType'); metadata.localCandidateType = report.stat('googLocalCandidateType');
metadata.remoteCandidateType = report.stat('googRemoteCandidateType');
// log pair as well so we can get nice pie charts // log pair as well so we can get nice pie charts
metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType'); metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType');
if (report.stat('googRemoteAddress').indexOf('[') === 0) { if (report.stat('googRemoteAddress').indexOf('[') === 0) {
metadata.ipv6 = true; metadata.ipv6 = true;
}
} }
} });
}); trackUsage('iceConnected', metadata);
trackUsage('iceConnected', metadata); }
}); });
} }
break; break;
...@@ -712,7 +772,7 @@ $(document).bind('joined.muc', function (event, jid, info) { ...@@ -712,7 +772,7 @@ $(document).bind('joined.muc', function (event, jid, info) {
VideoLayout.showFocusIndicator(); VideoLayout.showFocusIndicator();
// Add myself to the contact list. // Add myself to the contact list.
ContactList.addContact(jid); ContactList.addContact(jid, SettingsMenu.getEmail() || SettingsMenu.getUID());
// Once we've joined the muc show the toolbar // Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar(); ToolbarToggler.showToolbar();
...@@ -734,7 +794,12 @@ $(document).bind('entered.muc', function (event, jid, info, pres) { ...@@ -734,7 +794,12 @@ $(document).bind('entered.muc', function (event, jid, info, pres) {
console.log('is focus? ' + (focus ? 'true' : 'false')); console.log('is focus? ' + (focus ? 'true' : 'false'));
// Add Peer's container // Add Peer's container
VideoLayout.ensurePeerContainerExists(jid); var id = $(pres).find('>userID').text();
var email = $(pres).find('>email');
if(email.length > 0) {
id = email.text();
}
VideoLayout.ensurePeerContainerExists(jid,id);
if(APIConnector.isEnabled() && APIConnector.isEventEnabled("participantJoined")) if(APIConnector.isEnabled() && APIConnector.isEventEnabled("participantJoined"))
{ {
...@@ -785,14 +850,13 @@ $(document).bind('left.muc', function (event, jid) { ...@@ -785,14 +850,13 @@ $(document).bind('left.muc', function (event, jid) {
APIConnector.triggerEvent("participantLeft",{jid: jid}); APIConnector.triggerEvent("participantLeft",{jid: jid});
} }
delete jid2Ssrc[jid];
// Unlock large video // Unlock large video
if (focusedVideoSrc) if (focusedVideoSrc && focusedVideoSrc.jid === jid)
{ {
if (getJidFromVideoSrc(focusedVideoSrc) === jid) console.info("Focused video owner has left the conference");
{ focusedVideoSrc = null;
console.info("Focused video owner has left the conference");
focusedVideoSrc = null;
}
} }
connection.jingle.terminateByJid(jid); connection.jingle.terminateByJid(jid);
...@@ -844,8 +908,6 @@ $(document).bind('presence.muc', function (event, jid, info, pres) { ...@@ -844,8 +908,6 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
Object.keys(ssrc2jid).forEach(function (ssrc) { Object.keys(ssrc2jid).forEach(function (ssrc) {
if (ssrc2jid[ssrc] == jid) { if (ssrc2jid[ssrc] == jid) {
delete ssrc2jid[ssrc]; delete ssrc2jid[ssrc];
}
if (ssrc2videoType[ssrc] == jid) {
delete ssrc2videoType[ssrc]; delete ssrc2videoType[ssrc];
} }
}); });
...@@ -854,6 +916,7 @@ $(document).bind('presence.muc', function (event, jid, info, pres) { ...@@ -854,6 +916,7 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
//console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc')); //console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
var ssrcV = ssrc.getAttribute('ssrc'); var ssrcV = ssrc.getAttribute('ssrc');
ssrc2jid[ssrcV] = jid; ssrc2jid[ssrcV] = jid;
notReceivedSSRCs.push(ssrcV);
var type = ssrc.getAttribute('type'); var type = ssrc.getAttribute('type');
ssrc2videoType[ssrcV] = type; ssrc2videoType[ssrcV] = type;
...@@ -892,6 +955,13 @@ $(document).bind('presence.muc', function (event, jid, info, pres) { ...@@ -892,6 +955,13 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
"Jitsi Videobridge is currently unavailable. Please try again later!"); "Jitsi Videobridge is currently unavailable. Please try again later!");
} }
var id = $(pres).find('>userID').text();
var email = $(pres).find('>email');
if(email.length > 0) {
id = email.text();
}
Avatar.setUserAvatar(jid, id);
}); });
$(document).bind('presence.status.muc', function (event, jid, info, pres) { $(document).bind('presence.status.muc', function (event, jid, info, pres) {
...@@ -959,16 +1029,20 @@ $(document).bind('passwordrequired.main', function (event) { ...@@ -959,16 +1029,20 @@ $(document).bind('passwordrequired.main', function (event) {
* blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395 * blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395
* @returns {boolean} * @returns {boolean}
*/ */
function isVideoSrcDesktop(videoSrc) { function isVideoSrcDesktop(jid) {
// FIXME: fix this mapping mess... // FIXME: fix this mapping mess...
// figure out if large video is desktop stream or just a camera // figure out if large video is desktop stream or just a camera
if(!jid)
return false;
var isDesktop = false; var isDesktop = false;
if (localVideoSrc === videoSrc) { if (connection.emuc.myroomjid &&
Strophe.getResourceFromJid(connection.emuc.myroomjid) === jid) {
// local video // local video
isDesktop = isUsingScreenStream; isDesktop = isUsingScreenStream;
} else { } else {
// Do we have associations... // Do we have associations...
var videoSsrc = videoSrcToSsrc[videoSrc]; var videoSsrc = jid2Ssrc[jid];
if (videoSsrc) { if (videoSsrc) {
var videoType = ssrc2videoType[videoSsrc]; var videoType = ssrc2videoType[videoSsrc];
if (videoType) { if (videoType) {
...@@ -978,7 +1052,7 @@ function isVideoSrcDesktop(videoSrc) { ...@@ -978,7 +1052,7 @@ function isVideoSrcDesktop(videoSrc) {
console.error("No video type for ssrc: " + videoSsrc); console.error("No video type for ssrc: " + videoSsrc);
} }
} else { } else {
console.error("No ssrc for src: " + videoSrc); console.error("No ssrc for jid: " + jid);
} }
} }
return isDesktop; return isDesktop;
...@@ -1346,6 +1420,8 @@ $(document).ready(function () { ...@@ -1346,6 +1420,8 @@ $(document).ready(function () {
VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight); VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
}); });
document.getElementById('largeVideo').volume = 0;
if (!$('#settings').is(':visible')) { if (!$('#settings').is(':visible')) {
console.log('init'); console.log('init');
init(); init();
...@@ -1371,22 +1447,44 @@ $(document).ready(function () { ...@@ -1371,22 +1447,44 @@ $(document).ready(function () {
"showMethod": "fadeIn", "showMethod": "fadeIn",
"hideMethod": "fadeOut", "hideMethod": "fadeOut",
"reposition": function() { "reposition": function() {
if(Chat.isVisible() || ContactList.isVisible()) { if(PanelToggler.isVisible()) {
$("#toast-container").addClass("toast-bottom-right-center"); $("#toast-container").addClass("notification-bottom-right-center");
} else { } else {
$("#toast-container").removeClass("toast-bottom-right-center"); $("#toast-container").removeClass("notification-bottom-right-center");
} }
}, },
"newestOnTop": false "newestOnTop": false
} };
$('#settingsmenu>input').keyup(function(event){
if(event.keyCode === 13) {//enter
SettingsMenu.update();
}
})
}); });
$(window).bind('beforeunload', function () { $(window).bind('beforeunload', function () {
if (connection && connection.connected) { if (connection && connection.connected) {
connection.send($pres({type: "unavailable"})) // BAO // ensure signout
connection.disconnect(); $.ajax({
type: 'POST',
url: config.bosh,
async: false,
cache: false,
contentType: 'application/xml',
data: "<body rid='" + (connection.rid || connection._proto.rid)
+ "' xmlns='http://jabber.org/protocol/httpbind' sid='"
+ (connection.sid || connection._proto.sid)
+ "' type='terminate'><presence xmlns='jabber:client' type='unavailable'/></body>",
success: function (data) {
console.log('signed out');
console.log(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log('signout error', textStatus + ' (' + errorThrown + ')');
}
});
} }
disposeConference(true); disposeConference(true);
if(APIConnector.isEnabled()) if(APIConnector.isEnabled())
...@@ -1399,10 +1497,10 @@ function disposeConference(onUnload) { ...@@ -1399,10 +1497,10 @@ function disposeConference(onUnload) {
// FIXME: probably removing streams is not required and close() should // FIXME: probably removing streams is not required and close() should
// be enough // be enough
if (connection.jingle.localAudio) { if (connection.jingle.localAudio) {
handler.peerconnection.removeStream(connection.jingle.localAudio); handler.peerconnection.removeStream(connection.jingle.localAudio, onUnload);
} }
if (connection.jingle.localVideo) { if (connection.jingle.localVideo) {
handler.peerconnection.removeStream(connection.jingle.localVideo); handler.peerconnection.removeStream(connection.jingle.localVideo, onUnload);
} }
handler.peerconnection.close(); handler.peerconnection.close();
} }
...@@ -1562,7 +1660,7 @@ function onSelectedEndpointChanged(userJid) ...@@ -1562,7 +1660,7 @@ function onSelectedEndpointChanged(userJid)
dataChannel.send(JSON.stringify({ dataChannel.send(JSON.stringify({
'colibriClass': 'SelectedEndpointChangedEvent', 'colibriClass': 'SelectedEndpointChangedEvent',
'selectedEndpoint': (!userJid || userJid == null) 'selectedEndpoint': (!userJid || userJid == null)
? null : Strophe.getResourceFromJid(userJid) ? null : userJid
})); }));
return true; return true;
...@@ -1630,7 +1728,7 @@ function callSipButtonClicked() ...@@ -1630,7 +1728,7 @@ function callSipButtonClicked()
document.getElementById('sipNumber').focus(); document.getElementById('sipNumber').focus();
} }
); );
} }
} }
function hangup() { function hangup() {
...@@ -1665,3 +1763,14 @@ function hangup() { ...@@ -1665,3 +1763,14 @@ function hangup() {
); );
} }
$(document).on('videomuted.muc', function(event, jid, value) {
if(mediaStreams[jid] && mediaStreams[jid][MediaStream.VIDEO_TYPE]) {
var stream = mediaStreams[jid][MediaStream.VIDEO_TYPE];
var isMuted = (value === "true");
if (isMuted != stream.muted) {
stream.muted = isMuted;
Avatar.showUserAvatar(jid, isMuted);
}
}
});
...@@ -14,7 +14,7 @@ var Avatar = (function(my) { ...@@ -14,7 +14,7 @@ var Avatar = (function(my) {
} }
users[jid] = id; users[jid] = id;
} }
var url = getGravatarUrl(users[jid] || jid); var url = getGravatarUrl(users[jid] || jid, 100, jid); // BAO
var resourceJid = Strophe.getResourceFromJid(jid); var resourceJid = Strophe.getResourceFromJid(jid);
var thumbnail = $('#participant_' + resourceJid); var thumbnail = $('#participant_' + resourceJid);
var avatar = $('#avatar_' + resourceJid); var avatar = $('#avatar_' + resourceJid);
...@@ -102,7 +102,7 @@ var Avatar = (function(my) { ...@@ -102,7 +102,7 @@ var Avatar = (function(my) {
} }
var avatar = $("#activeSpeakerAvatar")[0]; var avatar = $("#activeSpeakerAvatar")[0];
var url = getGravatarUrl(users[jid], var url = getGravatarUrl(users[jid],
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE); interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE, jid); // BAO
if(jid === activeSpeakerJid && avatar.src === url) { if(jid === activeSpeakerJid && avatar.src === url) {
return; return;
} }
...@@ -122,19 +122,37 @@ var Avatar = (function(my) { ...@@ -122,19 +122,37 @@ var Avatar = (function(my) {
} }
function isUserMuted(jid) { function isUserMuted(jid) {
if(!mediaStreams[jid] || !mediaStreams[jid][MediaStream.VIDEO_TYPE]) { // XXX(gp) we may want to rename this method to something like
// isUserStreaming, for example.
if (jid && jid != connection.emuc.myroomjid) {
var resource = Strophe.getResourceFromJid(jid);
if (!VideoLayout.isInLastN(resource)) {
return true;
}
}
if (!mediaStreams[jid] || !mediaStreams[jid][MediaStream.VIDEO_TYPE]) {
return null; return null;
} }
return mediaStreams[jid][MediaStream.VIDEO_TYPE].muted; return mediaStreams[jid][MediaStream.VIDEO_TYPE].muted;
} }
function getGravatarUrl(id, size) { function getGravatarUrl(id, size, jid) {
if (connection.emuc.myroomjid == jid && config.userAvatar && config.userAvatar != "null")
{
return config.userAvatar; // BAO openfire avatars
} else if (connection.ofmuc.members[jid]) {
return connection.ofmuc.members[jid].avatar;
}
if(id === connection.emuc.myroomjid || !id) { if(id === connection.emuc.myroomjid || !id) {
id = SettingsMenu.getUID(); id = SettingsMenu.getUID();
} }
return 'https://www.gravatar.com/avatar/' +
MD5.hexdigest(id.trim().toLowerCase()) + return '//www.gravatar.com/avatar/' + MD5.hexdigest(id.trim().toLowerCase()) + "?d=mm&size=" + (size || "30");
"?d=retro&size=" + (size || "30");
} }
return my; return my;
......
var BottomToolbar = (function (my) { var BottomToolbar = (function (my) {
my.toggleChat = function() { my.toggleChat = function() {
if (ContactList.isVisible()) { PanelToggler.toggleChat();
buttonClick("#contactListButton", "active");
$('#contactlist').css('z-index', 4);
setTimeout(function() {
$('#contactlist').css('display', 'none');
$('#contactlist').css('z-index', 5);
}, 500);
}
Chat.toggleChat();
buttonClick("#chatBottomButton", "active");
}; };
my.toggleContactList = function() { my.toggleContactList = function() {
if (Chat.isVisible()) { PanelToggler.toggleContactList();
buttonClick("#chatBottomButton", "active");
setTimeout(function() {
$('#chatspace').css('display', 'none');
}, 500);
}
buttonClick("#contactListButton", "active");
ContactList.toggleContactList();
}; };
my.toggleFilmStrip = function() { my.toggleFilmStrip = function() {
......
...@@ -57,7 +57,7 @@ var Chat = (function (my) { ...@@ -57,7 +57,7 @@ var Chat = (function (my) {
var onTextAreaResize = function () { var onTextAreaResize = function () {
resizeChatConversation(); resizeChatConversation();
scrollChatToBottom(); Chat.scrollChatToBottom();
}; };
$('#usermsg').autosize({callback: onTextAreaResize}); $('#usermsg').autosize({callback: onTextAreaResize});
...@@ -144,112 +144,7 @@ var Chat = (function (my) { ...@@ -144,112 +144,7 @@ var Chat = (function (my) {
} }
}; };
/**
* Opens / closes the chat area.
*/
my.toggleChat = function () {
var chatspace = $('#chatspace');
var videospace = $('#videospace');
var chatSize = (Chat.isVisible()) ? [0, 0] : Chat.getChatSize();
var videospaceWidth = window.innerWidth - chatSize[0];
var videospaceHeight = window.innerHeight;
var videoSize
= getVideoSize(null, null, videospaceWidth, videospaceHeight);
var videoWidth = videoSize[0];
var videoHeight = videoSize[1];
var videoPosition = getVideoPosition(videoWidth,
videoHeight,
videospaceWidth,
videospaceHeight);
var horizontalIndent = videoPosition[0];
var verticalIndent = videoPosition[1];
var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
var thumbnailsWidth = thumbnailSize[0];
var thumbnailsHeight = thumbnailSize[1];
var completeFunction = Chat.isVisible() ?
function() {} : function () {
scrollChatToBottom();
chatspace.trigger('shown');
};
videospace.animate({right: chatSize[0],
width: videospaceWidth,
height: videospaceHeight},
{queue: false,
duration: 500,
complete: completeFunction});
$('#remoteVideos').animate({height: thumbnailsHeight},
{queue: false,
duration: 500});
$('#remoteVideos>span').animate({height: thumbnailsHeight,
width: thumbnailsWidth},
{queue: false,
duration: 500,
complete: function() {
$(document).trigger(
"remotevideo.resized",
[thumbnailsWidth,
thumbnailsHeight]);
}});
$('#largeVideoContainer').animate({ width: videospaceWidth,
height: videospaceHeight},
{queue: false,
duration: 500
});
$('#largeVideo').animate({ width: videoWidth,
height: videoHeight,
top: verticalIndent,
bottom: verticalIndent,
left: horizontalIndent,
right: horizontalIndent},
{ queue: false,
duration: 500
}
);
if (Chat.isVisible()) {
$("#toast-container").animate({right: '5px'},
{queue: false,
duration: 500});
chatspace.hide("slide", { direction: "right",
queue: false,
duration: 500});
}
else {
// Undock the toolbar when the chat is shown and if we're in a
// video mode.
if (VideoLayout.isLargeVideoVisible()) {
ToolbarToggler.dockToolbar(false);
}
$("#toast-container").animate({right: (chatSize[0] + 5) + 'px'},
{queue: false,
duration: 500});
chatspace.show("slide", { direction: "right",
queue: false,
duration: 500,
complete: function () {
// Request the focus in the nickname field or the chat input field.
if ($('#nickname').css('visibility') === 'visible') {
$('#nickinput').focus();
} else {
$('#usermsg').focus();
}
}
});
Chat.resizeChat();
}
};
/** /**
* Sets the chat conversation mode. * Sets the chat conversation mode.
...@@ -268,7 +163,7 @@ var Chat = (function (my) { ...@@ -268,7 +163,7 @@ var Chat = (function (my) {
* Resizes the chat area. * Resizes the chat area.
*/ */
my.resizeChat = function () { my.resizeChat = function () {
var chatSize = Chat.getChatSize(); var chatSize = PanelToggler.getPanelSize();
$('#chatspace').width(chatSize[0]); $('#chatspace').width(chatSize[0]);
$('#chatspace').height(chatSize[1]); $('#chatspace').height(chatSize[1]);
...@@ -276,20 +171,6 @@ var Chat = (function (my) { ...@@ -276,20 +171,6 @@ var Chat = (function (my) {
resizeChatConversation(); resizeChatConversation();
}; };
/**
* Returns the size of the chat.
*/
my.getChatSize = function () {
var availableHeight = window.innerHeight;
var availableWidth = window.innerWidth;
var chatWidth = 200;
if (availableWidth * 0.2 < 200)
chatWidth = availableWidth * 0.2;
return [chatWidth, availableHeight];
};
/** /**
* Indicates if the chat is currently visible. * Indicates if the chat is currently visible.
*/ */
...@@ -309,6 +190,16 @@ var Chat = (function (my) { ...@@ -309,6 +190,16 @@ var Chat = (function (my) {
$('#usermsg').focus(); $('#usermsg').focus();
}; };
/**
* Scrolls chat to the bottom.
*/
my.scrollChatToBottom = function() {
setTimeout(function () {
$('#chatconversation').scrollTop(
$('#chatconversation')[0].scrollHeight);
}, 5);
};
/** /**
* Adds the smileys container to the chat * Adds the smileys container to the chat
*/ */
...@@ -426,15 +317,6 @@ var Chat = (function (my) { ...@@ -426,15 +317,6 @@ var Chat = (function (my) {
} }
} }
/**
* Scrolls chat to the bottom.
*/
function scrollChatToBottom() {
setTimeout(function () {
$('#chatconversation').scrollTop(
$('#chatconversation')[0].scrollHeight);
}, 5);
}
/** /**
* Returns the current time in the format it is shown to the user * Returns the current time in the format it is shown to the user
......
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Forbidden</title>
</head>
<body>
<h1>Forbidden</h1>
<h4>This is a private folder</h4>
</body>
</html>
\ No newline at end of file
...@@ -44,5 +44,7 @@ var config = { ...@@ -44,5 +44,7 @@ var config = {
useBundle: true, useBundle: true,
enableRecording: false, enableRecording: false,
enableWelcomePage: true, enableWelcomePage: true,
enableSimulcast: false enableSimulcast: false,
enableFirefoxSupport: false //firefox support is still experimental, only one-to-one conferences with chrome focus
// will work when simulcast, bundle, mux, lastN and SCTP are disabled.
}; };
...@@ -20,22 +20,24 @@ var ContactList = (function (my) { ...@@ -20,22 +20,24 @@ var ContactList = (function (my) {
* Adds a contact for the given peerJid if such doesn't yet exist. * Adds a contact for the given peerJid if such doesn't yet exist.
* *
* @param peerJid the peerJid corresponding to the contact * @param peerJid the peerJid corresponding to the contact
* @param id the user's email or userId used to get the user's avatar
*/ */
my.ensureAddContact = function(peerJid) { my.ensureAddContact = function(peerJid, id) {
var resourceJid = Strophe.getResourceFromJid(peerJid); var resourceJid = Strophe.getResourceFromJid(peerJid);
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]'); var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if (!contact || contact.length <= 0) if (!contact || contact.length <= 0)
ContactList.addContact(peerJid); ContactList.addContact(peerJid,id);
}; };
/** /**
* Adds a contact for the given peer jid. * Adds a contact for the given peer jid.
* *
* @param peerJid the jid of the contact to add * @param peerJid the jid of the contact to add
* @param id the email or userId of the user
*/ */
my.addContact = function(peerJid) { my.addContact = function(peerJid, id) {
var resourceJid = Strophe.getResourceFromJid(peerJid); var resourceJid = Strophe.getResourceFromJid(peerJid);
var contactlist = $('#contactlist>ul'); var contactlist = $('#contactlist>ul');
...@@ -51,7 +53,7 @@ var ContactList = (function (my) { ...@@ -51,7 +53,7 @@ var ContactList = (function (my) {
} }
}; };
newContact.appendChild(createAvatar()); newContact.appendChild(createAvatar(id, peerJid)); // BAO
newContact.appendChild(createDisplayNameParagraph("Participant")); newContact.appendChild(createDisplayNameParagraph("Participant"));
var clElement = contactlist.get(0); var clElement = contactlist.get(0);
...@@ -87,95 +89,27 @@ var ContactList = (function (my) { ...@@ -87,95 +89,27 @@ var ContactList = (function (my) {
} }
}; };
/** my.setVisualNotification = function(show, stopGlowingIn) {
* Opens / closes the contact list area. var glower = $('#contactListButton');
*/ function stopGlowing() {
my.toggleContactList = function () { window.clearInterval(notificationInterval);
var contactlist = $('#contactlist'); notificationInterval = false;
var videospace = $('#videospace'); glower.removeClass('glowing');
if(!ContactList.isVisible()) {
var chatSize = (ContactList.isVisible()) ? [0, 0] : Chat.getChatSize(); glower.removeClass('active');
var videospaceWidth = window.innerWidth - chatSize[0]; }
var videospaceHeight = window.innerHeight; }
var videoSize
= getVideoSize(null, null, videospaceWidth, videospaceHeight);
var videoWidth = videoSize[0];
var videoHeight = videoSize[1];
var videoPosition = getVideoPosition(videoWidth,
videoHeight,
videospaceWidth,
videospaceHeight);
var horizontalIndent = videoPosition[0];
var verticalIndent = videoPosition[1];
var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
var thumbnailsWidth = thumbnailSize[0];
var thumbnailsHeight = thumbnailSize[1];
var completeFunction = ContactList.isVisible() ?
function() {} : function () { contactlist.trigger('shown');};
videospace.animate({right: chatSize[0],
width: videospaceWidth,
height: videospaceHeight},
{queue: false,
duration: 500,
complete: completeFunction
});
$('#remoteVideos').animate({height: thumbnailsHeight},
{queue: false,
duration: 500});
$('#remoteVideos>span').animate({height: thumbnailsHeight,
width: thumbnailsWidth},
{queue: false,
duration: 500,
complete: function() {
$(document).trigger(
"remotevideo.resized",
[thumbnailsWidth,
thumbnailsHeight]);
}});
$('#largeVideoContainer').animate({ width: videospaceWidth,
height: videospaceHeight},
{queue: false,
duration: 500
});
$('#largeVideo').animate({ width: videoWidth,
height: videoHeight,
top: verticalIndent,
bottom: verticalIndent,
left: horizontalIndent,
right: horizontalIndent},
{ queue: false,
duration: 500
});
if (ContactList.isVisible()) {
$("#toast-container").animate({right: '12px'},
{queue: false,
duration: 500});
$('#contactlist').hide("slide", { direction: "right",
queue: false,
duration: 500});
} else {
// Undock the toolbar when the chat is shown and if we're in a
// video mode.
if (VideoLayout.isLargeVideoVisible())
ToolbarToggler.dockToolbar(false);
$("#toast-container").animate({right: '212px'},
{queue: false,
duration: 500});
$('#contactlist').show("slide", { direction: "right",
queue: false,
duration: 500});
//stop the glowing of the contact list icon if (show && !notificationInterval) {
setVisualNotification(false); notificationInterval = window.setInterval(function () {
glower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
stopGlowing();
}
if(stopGlowingIn) {
setTimeout(stopGlowing, stopGlowingIn);
} }
}; };
...@@ -191,21 +125,33 @@ var ContactList = (function (my) { ...@@ -191,21 +125,33 @@ var ContactList = (function (my) {
$("#numberOfParticipants").text(''); $("#numberOfParticipants").text('');
numberOfContacts += delta; numberOfContacts += delta;
} else if(numberOfContacts !== 0 && !ContactList.isVisible()) { } else if(numberOfContacts !== 0 && !ContactList.isVisible()) {
setVisualNotification(true); ContactList.setVisualNotification(true);
numberOfContacts += delta; numberOfContacts += delta;
$("#numberOfParticipants").text(numberOfContacts); $("#numberOfParticipants").text(numberOfContacts);
} }
}; }
/** /**
* Creates the avatar element. * Creates the avatar element.
* *
* @return the newly created avatar element * @return the newly created avatar element
*/ */
function createAvatar() { function createAvatar(id, peerJid) { // BAO
var avatar = document.createElement('i'); var avatar = document.createElement('img');
avatar.className = "icon-avatar avatar"; avatar.className = "icon-avatar avatar";
if (connection.emuc.myroomjid == peerJid && config.userAvatar && config.userAvatar != "null")
{
avatar.src = config.userAvatar;
} else if (connection.ofmuc.members[peerJid] && connection.ofmuc.members[peerJid].avatar) {
avatar.src = connection.ofmuc.members[peerJid].avatar;
} else {
avatar.src = "//www.gravatar.com/avatar/" + id + "?d=mm&size=30";
}
return avatar; return avatar;
} }
...@@ -221,33 +167,6 @@ var ContactList = (function (my) { ...@@ -221,33 +167,6 @@ var ContactList = (function (my) {
return p; return p;
} }
/**
* Shows/hides a visual notification, indicating that a new user has joined
* the conference.
*/
function setVisualNotification(show, stopGlowingIn) {
var glower = $('#contactListButton');
function stopGlowing() {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('glowing');
if(!ContactList.isVisible()) {
glower.removeClass('active');
}
}
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
stopGlowing();
}
if(stopGlowingIn) {
setTimeout(stopGlowing, stopGlowingIn);
}
}
/** /**
* Indicates that the display name has changed. * Indicates that the display name has changed.
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
margin-right: 10px; margin-right: 10px;
vertical-align: middle; vertical-align: middle;
font-size: 22pt; font-size: 22pt;
border-radius: 20px;
} }
#contactlist .clickable { #contactlist .clickable {
......
...@@ -112,4 +112,8 @@ ...@@ -112,4 +112,8 @@
.icon-connection:before { .icon-connection:before {
line-height: normal; line-height: normal;
content: "\e61a"; content: "\e61a";
}
.icon-settings:before {
content: "\e61b";
} }
\ No newline at end of file
...@@ -13,8 +13,7 @@ html, body{ ...@@ -13,8 +13,7 @@ html, body{
overflow-x: hidden; overflow-x: hidden;
} }
#chatspace, .right-panel {
#contactlist {
display:none; display:none;
position:absolute; position:absolute;
float: right; float: right;
...@@ -38,10 +37,6 @@ html, body{ ...@@ -38,10 +37,6 @@ html, body{
display:none; display:none;
} }
#settingsButton {
visibility: hidden;
}
.toolbar_span { .toolbar_span {
display: inline-block; display: inline-block;
position: relative; position: relative;
......
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
#remoteVideos .videocontainer { #remoteVideos .videocontainer {
display: inline-block; display: inline-block;
background-image:url(../images/avatar1.png); background-color: black;
background-repeat: no-repeat;
background-position: 45;
background-size: contain; background-size: contain;
border-radius:8px; border-radius:8px;
border: 2px solid #212425; border: 2px solid #212425;
...@@ -102,6 +104,11 @@ ...@@ -102,6 +104,11 @@
text-align: center; text-align: center;
} }
#largeVideo
{
object-fit: cover;
}
#presentation, #presentation,
#etherpad, #etherpad,
#localVideoWrapper>video, #localVideoWrapper>video,
...@@ -115,10 +122,6 @@ ...@@ -115,10 +122,6 @@
height: 100%; height: 100%;
} }
.dominantspeaker {
background: #000 !important;
}
#etherpad, #etherpad,
#presentation { #presentation {
text-align: center; text-align: center;
...@@ -378,3 +381,19 @@ ...@@ -378,3 +381,19 @@
#mixedstream { #mixedstream {
display:none !important; display:none !important;
} }
#activeSpeakerAvatar {
visibility: hidden;
width: 100px;
height: 100px;
margin: auto;
position: relative;
border-radius: 50px;
}
.userAvatar {
height: 100%;
position: absolute;
left: 35px;
border-radius: 200px;
}
...@@ -26,8 +26,7 @@ function onDataChannel(event) ...@@ -26,8 +26,7 @@ function onDataChannel(event)
// when the data channel becomes available, tell the bridge about video // when the data channel becomes available, tell the bridge about video
// selections so that it can do adaptive simulcast, // selections so that it can do adaptive simulcast,
var largeVideoSrc = $('#largeVideo').attr('src'); var userJid = VideoLayout.getLargeVideoState().userJid;
var userJid = getJidFromVideoSrc(largeVideoSrc);
// we want the notification to trigger even if userJid is undefined, // we want the notification to trigger even if userJid is undefined,
// or null. // or null.
onSelectedEndpointChanged(userJid); onSelectedEndpointChanged(userJid);
......
...@@ -34,4 +34,5 @@ ...@@ -34,4 +34,5 @@
<glyph unicode="&#xe618;" d="M797.086 112.301c-0.059 0.163-0.119 0.328-0.16 0.485-71.399-45.638-151.782-69.931-234.023-69.931-0.013 0-0.021 0-0.028 0-122.52 0-237.501 52.772-315.469 144.741-99.778 117.698-134.252 329.954-73.022 427.789 4.004-1.662 7.875-3.233 11.68-4.773 13.585-5.511 26.413-10.716 42.305-19.096 6.063-3.202 12.338-4.812 18.673-4.812 11.714 0 22.6 5.648 29.848 15.486 7.815 10.617 10.313 24.778 6.538 36.951l-3.525 11.41c-10.687 34.59-21.723 70.354-34.211 105.078-9.983 27.765-22.399 62.327-59.226 62.327-12.057 0-26.037-3.656-46.73-12.204-44.294-18.319-71.058-29.961-114.534-49.81-15.102-6.887-25.234-22.698-25.203-39.343 0.028-15.842 8.992-29.337 23.975-36.115 18.208-8.257 30.536-13.716 43.468-19.447l10.687-4.753c-101.938-259.102 24.803-526.458 211.314-639.212 83.497-50.474 178.5-77.14 274.769-77.14h0.041c102.72 0 205.561 31.099 284.501 85.198-31.729 28.803-45.566 69.167-51.671 87.171zM1098.203 210.090c-18.113 8.577-30.356 14.258-43.221 20.244l-10.496 4.892c106.448 257.268-15.569 526.801-200.067 642.788-85.36 53.663-183.123 82.032-282.716 82.032-104.848 0-206.41-30.593-285.967-86.165l-5.385-3.764c31.597-27.564 45.86-66.788 52.917-86.41 72.926 47.94 155.675 73.409 239.895 73.409 125.407 0 242.142-54.785 320.294-150.316 97.683-119.447 128.439-332.255 65.498-429.015-3.989 1.736-7.815 3.385-11.624 4.998-13.471 5.759-26.204 11.18-41.954 19.821-6.203 3.424-12.645 5.155-19.212 5.155-11.585 0-22.399-5.558-29.69-15.267-7.813-10.434-10.478-24.432-6.966-36.515l3.279-11.301c10.096-34.845 20.531-70.857 32.412-105.842 9.588-28.238 21.514-63.382 59.179-63.382 11.843 0 25.577 3.424 45.881 11.399 44.351 17.439 71.319 28.601 115.409 47.777 15.19 6.623 25.601 22.252 25.859 38.894 0.281 15.822-8.445 29.499-23.325 36.569z" horiz-adv-x="1122" /> <glyph unicode="&#xe618;" d="M797.086 112.301c-0.059 0.163-0.119 0.328-0.16 0.485-71.399-45.638-151.782-69.931-234.023-69.931-0.013 0-0.021 0-0.028 0-122.52 0-237.501 52.772-315.469 144.741-99.778 117.698-134.252 329.954-73.022 427.789 4.004-1.662 7.875-3.233 11.68-4.773 13.585-5.511 26.413-10.716 42.305-19.096 6.063-3.202 12.338-4.812 18.673-4.812 11.714 0 22.6 5.648 29.848 15.486 7.815 10.617 10.313 24.778 6.538 36.951l-3.525 11.41c-10.687 34.59-21.723 70.354-34.211 105.078-9.983 27.765-22.399 62.327-59.226 62.327-12.057 0-26.037-3.656-46.73-12.204-44.294-18.319-71.058-29.961-114.534-49.81-15.102-6.887-25.234-22.698-25.203-39.343 0.028-15.842 8.992-29.337 23.975-36.115 18.208-8.257 30.536-13.716 43.468-19.447l10.687-4.753c-101.938-259.102 24.803-526.458 211.314-639.212 83.497-50.474 178.5-77.14 274.769-77.14h0.041c102.72 0 205.561 31.099 284.501 85.198-31.729 28.803-45.566 69.167-51.671 87.171zM1098.203 210.090c-18.113 8.577-30.356 14.258-43.221 20.244l-10.496 4.892c106.448 257.268-15.569 526.801-200.067 642.788-85.36 53.663-183.123 82.032-282.716 82.032-104.848 0-206.41-30.593-285.967-86.165l-5.385-3.764c31.597-27.564 45.86-66.788 52.917-86.41 72.926 47.94 155.675 73.409 239.895 73.409 125.407 0 242.142-54.785 320.294-150.316 97.683-119.447 128.439-332.255 65.498-429.015-3.989 1.736-7.815 3.385-11.624 4.998-13.471 5.759-26.204 11.18-41.954 19.821-6.203 3.424-12.645 5.155-19.212 5.155-11.585 0-22.399-5.558-29.69-15.267-7.813-10.434-10.478-24.432-6.966-36.515l3.279-11.301c10.096-34.845 20.531-70.857 32.412-105.842 9.588-28.238 21.514-63.382 59.179-63.382 11.843 0 25.577 3.424 45.881 11.399 44.351 17.439 71.319 28.601 115.409 47.777 15.19 6.623 25.601 22.252 25.859 38.894 0.281 15.822-8.445 29.499-23.325 36.569z" horiz-adv-x="1122" />
<glyph unicode="&#xe619;" d="M46.993 961.7c461.234 0 553.793 0 1015.024 0 35.919 0 53.356-25.959 53.356-57.959-0.581-303.259-0.325-606.488-0.449-909.809 0-43.984-13.203-57.058-57.703-57.058-443.072-0.126-556.453-0.126-999.553 0-44.534 0-57.799 13.009-57.799 57.058-0.098 303.257 0.485 608.072-0.093 911.329-0.034 26.21 11.301 53.761 47.217 56.439zM311.405 450.298c0-119.045-0.072-172.168 0.057-291.249 0.036-50.043 11.208-61.050 62.12-61.050 233.352 0 137.075 0 370.522 0 47.075 0 59.249 11.982 59.249 58.095 0.126 239.111 0.126 346.338 0 585.389 0 48.138-10.687 58.991-57.768 58.991-235.323 0.101-140.844 0.101-376.157 0-47.044 0-57.93-11.043-57.966-58.89-0.129-119.109-0.057-172.209-0.057-291.287zM153.944 838.566c-74.929-0.062-66.687 5.958-66.845-66.685-0.201-63.95-7.054-63.534 62.528-63.372 72.999 0.194 67.201-3.764 67.302 67.554 0 67.722 4.087 62.595-62.985 62.502zM963.644 838.566c-71.159-0.034-65.56 6.185-65.751-65.364-0.129-67.302-4.508-64.693 64.528-64.693 73.089 0 65.299-2.031 65.299 66.238-0.003 68.646 6.956 63.911-64.076 63.818zM216.828 122.408c0.359 73.094 4.639 66.914-67.358 67.17-68.104 0.191-62.569 2.763-62.407-63.31 0.129-73.476-6.954-66.52 67.074-66.649 66.042-0.065 63.142-6.056 62.691 62.789zM1027.718 124.4c0.134 68.334 6.443 65.304-63.297 65.178-70.132-0.132-66.656 5.793-66.527-65.304 0.129-70.645-4.384-64.721 63.756-64.657 71.995 0.132 66.202-6.698 66.068 64.783zM1027.718 342.077c0 70.55 7.219 66.842-67.485 66.522-0.898 0-1.873 0-2.838 0-59.375 0-59.375 0-59.375-58.023 0-77.922-6.443-69.936 69.293-70.196 66.076-0.387 60.539-3.091 60.405 61.697zM151.307 489.873c68.295-0.163 65.815-5.568 65.624 62.982-0.194 71.128 4.895 64.917-66.014 65.010-69.905 0.101-63.813 4.704-63.885-63.978-0.062-67.431-5.7-64.463 64.275-64.014zM961.263 489.873c72.511-0.258 66.589-4.603 66.455 64.494 0 68.558 6.185 63.537-64.267 63.498-70.196-0.028-65.686 6.053-65.498-65.493 0.132-62.5 0.067-62.5 63.31-62.5zM150.399 280.38c71.004 0 66.659-6.567 66.466 64.528-0.163 63.694-0.036 63.501-65.013 63.756-70.805 0.258-64.822 2.673-64.822-63.756 0.036-69.167-5.919-64.788 63.369-64.528z" horiz-adv-x="1115" /> <glyph unicode="&#xe619;" d="M46.993 961.7c461.234 0 553.793 0 1015.024 0 35.919 0 53.356-25.959 53.356-57.959-0.581-303.259-0.325-606.488-0.449-909.809 0-43.984-13.203-57.058-57.703-57.058-443.072-0.126-556.453-0.126-999.553 0-44.534 0-57.799 13.009-57.799 57.058-0.098 303.257 0.485 608.072-0.093 911.329-0.034 26.21 11.301 53.761 47.217 56.439zM311.405 450.298c0-119.045-0.072-172.168 0.057-291.249 0.036-50.043 11.208-61.050 62.12-61.050 233.352 0 137.075 0 370.522 0 47.075 0 59.249 11.982 59.249 58.095 0.126 239.111 0.126 346.338 0 585.389 0 48.138-10.687 58.991-57.768 58.991-235.323 0.101-140.844 0.101-376.157 0-47.044 0-57.93-11.043-57.966-58.89-0.129-119.109-0.057-172.209-0.057-291.287zM153.944 838.566c-74.929-0.062-66.687 5.958-66.845-66.685-0.201-63.95-7.054-63.534 62.528-63.372 72.999 0.194 67.201-3.764 67.302 67.554 0 67.722 4.087 62.595-62.985 62.502zM963.644 838.566c-71.159-0.034-65.56 6.185-65.751-65.364-0.129-67.302-4.508-64.693 64.528-64.693 73.089 0 65.299-2.031 65.299 66.238-0.003 68.646 6.956 63.911-64.076 63.818zM216.828 122.408c0.359 73.094 4.639 66.914-67.358 67.17-68.104 0.191-62.569 2.763-62.407-63.31 0.129-73.476-6.954-66.52 67.074-66.649 66.042-0.065 63.142-6.056 62.691 62.789zM1027.718 124.4c0.134 68.334 6.443 65.304-63.297 65.178-70.132-0.132-66.656 5.793-66.527-65.304 0.129-70.645-4.384-64.721 63.756-64.657 71.995 0.132 66.202-6.698 66.068 64.783zM1027.718 342.077c0 70.55 7.219 66.842-67.485 66.522-0.898 0-1.873 0-2.838 0-59.375 0-59.375 0-59.375-58.023 0-77.922-6.443-69.936 69.293-70.196 66.076-0.387 60.539-3.091 60.405 61.697zM151.307 489.873c68.295-0.163 65.815-5.568 65.624 62.982-0.194 71.128 4.895 64.917-66.014 65.010-69.905 0.101-63.813 4.704-63.885-63.978-0.062-67.431-5.7-64.463 64.275-64.014zM961.263 489.873c72.511-0.258 66.589-4.603 66.455 64.494 0 68.558 6.185 63.537-64.267 63.498-70.196-0.028-65.686 6.053-65.498-65.493 0.132-62.5 0.067-62.5 63.31-62.5zM150.399 280.38c71.004 0 66.659-6.567 66.466 64.528-0.163 63.694-0.036 63.501-65.013 63.756-70.805 0.258-64.822 2.673-64.822-63.756 0.036-69.167-5.919-64.788 63.369-64.528z" horiz-adv-x="1115" />
<glyph unicode="&#xe61a;" d="M3.881 146.835h220.26v-210.835h-220.26v210.835zM308.817 350.143h220.27v-414.143h-220.27v414.143zM613.764 553.412h220.268v-617.412h-220.268v617.412zM918.685 756.715h220.265v-820.715h-220.265v820.715zM1223.629 960h220.263v-1024h-220.263v1024z" horiz-adv-x="1444" /> <glyph unicode="&#xe61a;" d="M3.881 146.835h220.26v-210.835h-220.26v210.835zM308.817 350.143h220.27v-414.143h-220.27v414.143zM613.764 553.412h220.268v-617.412h-220.268v617.412zM918.685 756.715h220.265v-820.715h-220.265v820.715zM1223.629 960h220.263v-1024h-220.263v1024z" horiz-adv-x="1444" />
<glyph unicode="&#xe61b;" d="M526.071 234.749c-28.637-30.869-56.465-60.861-84.282-90.859-51.578-55.636-103.047-111.376-154.842-166.832-7.606-8.135-15.958-16.1-25.317-22.012-28.075-17.708-58.31-18.090-88.472-6.492-59.84 23.028-80.004 90.727-59.734 139.234 5.413 12.95 13.721 23.601 23.709 33.173 70.256 67.351 140.506 134.717 210.76 202.077 15.638 14.993 31.264 29.995 47.364 45.45-9.302 9.529-18.386 18.833-27.451 28.137-12.122 12.442-13.234 20.28-5.067 35.498 4.735 8.816 4.789 8.878-2.627 16.198-20.012 19.72-40.168 39.198-63.498 55.188-27.167 18.624-57.161 24.233-89.083 19.849-53.402-7.328-91.609-38.372-121.413-81.046-12.774-18.299-15.365-40.313-17.517-61.875-3.23-32.245-2.415-64.479 2.209-96.597 1.654-11.515-3.863-16.539-13.835-11.175-8.306 4.448-16.095 11.048-22.115 18.353-15.574 18.89-22.223 42.042-27.474 65.395-12.955 57.652-8.86 114.49 12.191 169.495 32.345 84.537 79.743 159.571 145.953 221.932 13.659 12.857 176.841 180.564 202.944 207.021 7.493 7.599 14.895 7.635 22.393 0.028 43.009-43.641 85.985-87.316 128.927-131.029 8.117-8.267 8.019-15.097-0.222-23.49-26.339-26.834-52.726-53.627-79.106-80.419-6.244-6.334-97.34-82.437-73.027-128.816 22.693-25.090 46.196-49.449 69.575-73.904 1.189-1.238 4.686-1.386 6.523-0.632 3.63 1.499 6.848 3.997 10.248 6.066 9.745 5.94 19.545 4.918 27.812-3.083 11.755-11.381 23.405-22.858 35.392-34.59 4.807 4.575 9.939 9.41 15.027 14.294 27.128 26.039 54.272 52.071 81.351 78.146 16.413 15.778 18.652 28.418 11.038 49.658-10.473 29.221-14.356 59.677-13.85 90.624 1.017 61.045 20.438 115.334 61.003 161.416 32.825 37.286 72.054 64.311 121.643 74.325 35.227 7.101 69.139 4.513 100.663-14.026 6.365-3.752 11.908-9.007 17.455-14.005 3.491-3.125 3.153-6.236-0.565-9.98-42.503-42.885-84.772-86.013-127.154-129.035-12.442-12.638-12.356-23.167 0.196-35.914 40.344-40.978 80.597-82.050 120.936-123.052 10.076-10.233 19.537-10.021 29.504 0.134 43.195 44.077 86.449 88.090 129.706 132.118 1.21 1.233 2.572 2.322 5.135 4.624 5.491-5.893 11.895-10.924 15.961-17.406 19.452-30.944 22.608-64.83 17.073-100.25-14.253-91.080-97.188-175.638-197.712-190.123-39.977-5.764-79.372-2.562-118.067 9.031-5.898 1.775-11.541 4.629-17.538 5.829-12.47 2.474-23.872-0.366-32.74-9.877-30.921-33.168-61.674-66.484-92.474-99.758-0.73-0.805-1.349-1.718-0.181-1.099 8.992-10.006 17.354-20.662 27.061-29.94 81.064-77.54 164.91-151.986 250.882-224.063 9.936-8.347 10.274-15.695 1.040-25.1-42.338-43.068-84.689-86.111-127.059-129.154-9.413-9.575-16.846-9.152-25.291 1.295-76.686 94.78-156.8 186.609-239.707 276.002-1.334 1.453-2.562 3.029-4.257 5.042z" horiz-adv-x="1105" />
</font></defs></svg> </font></defs></svg>
\ No newline at end of file
{ {
"IcoMoonType": "selection", "IcoMoonType": "selection",
"icons": [ "icons": [
{
"icon": {
"paths": [
"M526.071 725.251c-28.637 30.869-56.465 60.861-84.282 90.859-51.578 55.636-103.047 111.376-154.842 166.832-7.606 8.135-15.958 16.1-25.317 22.012-28.075 17.708-58.31 18.090-88.472 6.492-59.84-23.028-80.004-90.727-59.734-139.234 5.413-12.95 13.721-23.601 23.709-33.173 70.256-67.351 140.506-134.717 210.76-202.077 15.638-14.993 31.264-29.995 47.364-45.45-9.302-9.529-18.386-18.833-27.451-28.137-12.122-12.442-13.234-20.28-5.067-35.498 4.735-8.816 4.789-8.878-2.627-16.198-20.012-19.72-40.168-39.198-63.498-55.188-27.167-18.624-57.161-24.233-89.083-19.849-53.402 7.328-91.609 38.372-121.413 81.046-12.774 18.299-15.365 40.313-17.517 61.875-3.23 32.245-2.415 64.479 2.209 96.597 1.654 11.515-3.863 16.539-13.835 11.175-8.306-4.448-16.095-11.048-22.115-18.353-15.574-18.89-22.223-42.042-27.474-65.395-12.955-57.652-8.86-114.49 12.191-169.495 32.345-84.537 79.743-159.571 145.953-221.932 13.659-12.857 176.841-180.564 202.944-207.021 7.493-7.599 14.895-7.635 22.393-0.028 43.009 43.641 85.985 87.316 128.927 131.029 8.117 8.267 8.019 15.097-0.222 23.49-26.339 26.834-52.726 53.627-79.106 80.419-6.244 6.334-97.34 82.437-73.027 128.816 22.693 25.090 46.196 49.449 69.575 73.904 1.189 1.238 4.686 1.386 6.523 0.632 3.63-1.499 6.848-3.997 10.248-6.066 9.745-5.94 19.545-4.918 27.812 3.083 11.755 11.381 23.405 22.858 35.392 34.59 4.807-4.575 9.939-9.41 15.027-14.294 27.128-26.039 54.272-52.071 81.351-78.146 16.413-15.778 18.652-28.418 11.038-49.658-10.473-29.221-14.356-59.677-13.85-90.624 1.017-61.045 20.438-115.334 61.003-161.416 32.825-37.286 72.054-64.311 121.643-74.325 35.227-7.101 69.139-4.513 100.663 14.026 6.365 3.752 11.908 9.007 17.455 14.005 3.491 3.125 3.153 6.236-0.565 9.98-42.503 42.885-84.772 86.013-127.154 129.035-12.442 12.638-12.356 23.167 0.196 35.914 40.344 40.978 80.597 82.050 120.936 123.052 10.076 10.233 19.537 10.021 29.504-0.134 43.195-44.077 86.449-88.090 129.706-132.118 1.21-1.233 2.572-2.322 5.135-4.624 5.491 5.893 11.895 10.924 15.961 17.406 19.452 30.944 22.608 64.83 17.073 100.25-14.253 91.080-97.188 175.638-197.712 190.123-39.977 5.764-79.372 2.562-118.067-9.031-5.898-1.775-11.541-4.629-17.538-5.829-12.47-2.474-23.872 0.366-32.74 9.877-30.921 33.168-61.674 66.484-92.474 99.758-0.73 0.805-1.349 1.718-0.181 1.099 8.992 10.006 17.354 20.662 27.061 29.94 81.064 77.54 164.91 151.986 250.882 224.063 9.936 8.347 10.274 15.695 1.040 25.1-42.338 43.068-84.689 86.111-127.059 129.154-9.413 9.575-16.846 9.152-25.291-1.295-76.686-94.78-156.8-186.609-239.707-276.002-1.334-1.453-2.562-3.029-4.257-5.042z"
],
"attrs": [
{
"opacity": 1,
"visibility": false
}
],
"width": 1105,
"grid": 0,
"tags": [
"settings"
]
},
"attrs": [
{
"opacity": 1,
"visibility": false
}
],
"properties": {
"order": 1,
"id": 33,
"prevSize": 32,
"code": 58907,
"name": "settings"
},
"setIdx": 0,
"iconIdx": 0
},
{ {
"icon": { "icon": {
"paths": [ "paths": [
"M1223.129 242.783l-180.128 175.796v-217.716c0-74.673-59.512-135.496-132.599-135.496h-634.716c-73.084 0-132.596 60.823-132.596 135.496v609.237c0 74.673 59.512 135.496 132.596 135.496h634.716c73.084 0 132.599-60.82 132.599-135.496v-172.679l193.45 153.712c48.784 35.558 96.695-5.178 96.695-40.424v-483.533c-0.003-35.248-55.897-71.306-110.017-24.393zM601.169 760.065c-141.111 0-255.524-114.411-255.524-255.521s114.411-255.521 255.524-255.521c141.108 0 255.519 114.411 255.519 255.521-0 141.113-114.408 255.521-255.519 255.521z", "M1223.129 242.783l-180.128 175.796v-217.716c0-74.673-59.512-135.496-132.599-135.496h-634.716c-73.084 0-132.596 60.823-132.596 135.496v609.237c0 74.673 59.512 135.496 132.596 135.496h634.716c73.084 0 132.599-60.82 132.599-135.496v-172.679l193.45 153.712c48.784 35.558 96.695-5.178 96.695-40.424v-483.533c-0.003-35.248-55.897-71.306-110.017-24.393zM601.169 760.065c-141.111 0-255.524-114.411-255.524-255.521s114.411-255.521 255.524-255.521c141.108 0 255.519 114.411 255.519 255.521-0 141.113-114.408 255.521-255.519 255.521z",
"M599.045 359.751c-80.474 0-145.727 65.253-145.727 145.729 0 80.471 65.25 145.727 145.727 145.727s145.729-65.256 145.729-145.727c0-80.474-65.253-145.729-145.729-145.729z" "M599.045 359.751c-80.474 0-145.727 65.253-145.727 145.729 0 80.471 65.25 145.727 145.727 145.727s145.729-65.256 145.729-145.727c0-80.474-65.253-145.729-145.729-145.729z"
], ],
"width": 1334,
"attrs": [ "attrs": [
{ {
"opacity": 1, "opacity": 1,
...@@ -17,11 +51,10 @@ ...@@ -17,11 +51,10 @@
"visibility": false "visibility": false
} }
], ],
"width": 1334,
"grid": 0,
"tags": [ "tags": [
"webCam" "webCam"
] ],
"grid": 0
}, },
"attrs": [ "attrs": [
{ {
...@@ -714,7 +747,7 @@ ...@@ -714,7 +747,7 @@
"ligatures": "" "ligatures": ""
}, },
"setIdx": 0, "setIdx": 0,
"iconIdx": 26 "iconIdx": 25
}, },
{ {
"icon": { "icon": {
...@@ -740,7 +773,7 @@ ...@@ -740,7 +773,7 @@
"ligatures": "" "ligatures": ""
}, },
"setIdx": 0, "setIdx": 0,
"iconIdx": 27 "iconIdx": 26
}, },
{ {
"icon": { "icon": {
...@@ -765,7 +798,7 @@ ...@@ -765,7 +798,7 @@
"ligatures": "" "ligatures": ""
}, },
"setIdx": 0, "setIdx": 0,
"iconIdx": 28 "iconIdx": 27
} }
], ],
"height": 1024, "height": 1024,
...@@ -775,6 +808,7 @@ ...@@ -775,6 +808,7 @@
"preferences": { "preferences": {
"showGlyphs": true, "showGlyphs": true,
"showQuickUse": true, "showQuickUse": true,
"showQuickUse2": true,
"showSVGs": true, "showSVGs": true,
"fontPref": { "fontPref": {
"prefix": "icon-", "prefix": "icon-",
...@@ -791,7 +825,8 @@ ...@@ -791,7 +825,8 @@
}, },
"imagePref": { "imagePref": {
"prefix": "icon-", "prefix": "icon-",
"png": true "png": true,
"useClassSelector": true
}, },
"historySize": 100, "historySize": 100,
"showCodes": true, "showCodes": true,
......
...@@ -55,6 +55,8 @@ config.page.configuration.audiomixer.enabled=Enabled ...@@ -55,6 +55,8 @@ config.page.configuration.audiomixer.enabled=Enabled
config.page.configuration.audiomixer.disabled=Disbled config.page.configuration.audiomixer.disabled=Disbled
config.page.configuration.audiomixer.enabled_description=Audio Mixer enabled config.page.configuration.audiomixer.enabled_description=Audio Mixer enabled
config.page.configuration.audiomixer.disabled_description=Audio Mixer disabled config.page.configuration.audiomixer.disabled_description=Audio Mixer disabled
config.page.configuration.record.path=Recording Path
config.page.configuration.record.secret=Recording Password/Secret
ofmeet.conference.summary=Below is an overview of meetings. ofmeet.conference.summary=Below is an overview of meetings.
ofmeet.conference.expired=Conference has been expired. ofmeet.conference.expired=Conference has been expired.
ofmeet.summary.conferences=Total Conferences ofmeet.summary.conferences=Total Conferences
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
<script src="libs/jquery-2.1.1.min.js"></script> <script src="libs/jquery-2.1.1.min.js"></script>
<script src="/ofmeet/config"></script><!-- BAO --> <script src="/ofmeet/config"></script><!-- BAO -->
<script src="simulcast.js?v=7"></script><!-- simulcast handling --> <script src="simulcast.js?v=7"></script><!-- simulcast handling -->
<script src="libs/strophe/strophe.jingle.adapter.js?v=3"></script><!-- strophe.jingle bundles -->
<script src="libs/strophe/strophe.js?v=1"></script><!-- BAO --> <script src="libs/strophe/strophe.js?v=1"></script><!-- BAO -->
<script src="libs/strophe/strophe.openfire.js?v=1"></script><!-- BAO --> <script src="libs/strophe/strophe.openfire.js?v=1"></script><!-- BAO -->
<script src="libs/strophe/strophe.jingle.adapter.js?v=3"></script><!-- strophe.jingle bundles -->
<script src="libs/strophe/strophe.connection.mgr.js?v=1"></script><!-- BAO --> <script src="libs/strophe/strophe.connection.mgr.js?v=1"></script><!-- BAO -->
<script src="libs/strophe/strophe.workgroup.js?v=1"></script><!-- BAO --> <script src="libs/strophe/strophe.workgroup.js?v=1"></script><!-- BAO -->
<script src="libs/strophe/strophe.disco.min.js?v=1"></script> <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
...@@ -31,18 +31,19 @@ ...@@ -31,18 +31,19 @@
<script src="libs/rayo.js?v=1"></script> <script src="libs/rayo.js?v=1"></script>
<script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib --> <script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib --> <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="interface_config.js?v=3"></script>
<script src="libs/toastr.js?v=1"></script><!-- notifications lib --> <script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
<script src="muc.js?v=16"></script><!-- simple MUC library --> <script src="interface_config.js?v=4"></script>
<script src="muc.js?v=17"></script><!-- simple MUC library -->
<script src="ofmuc.js?v=1"></script><!-- BAO --> <script src="ofmuc.js?v=1"></script><!-- BAO -->
<script src="estos_log.js?v=2"></script><!-- simple stanza logger --> <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
<script src="ofmeet-screenshare.js?v=1"></script><!-- BAO --> <script src="ofmeet-screenshare.js?v=1"></script><!-- BAO -->
<script src="data_channels.js?v=3"></script><!-- data channels --> <script src="data_channels.js?v=3"></script><!-- data channels -->
<script src="app.js?v=20"></script><!-- application logic --> <script src="app.js?v=21"></script><!-- application logic -->
<script src="commands.js?v=1"></script><!-- application logic --> <script src="commands.js?v=1"></script><!-- application logic -->
<script src="chat.js?v=14"></script><!-- chat logic --> <script src="chat.js?v=15"></script><!-- chat logic -->
<script src="contact_list.js?v=6"></script><!-- contact list logic --> <script src="contact_list.js?v=7"></script><!-- contact list logic -->
<script src="util.js?v=6"></script><!-- utility functions --> <script src="side_panel_toggler.js?v=1"></script>
<script src="util.js?v=7"></script><!-- utility functions -->
<script src="etherpad.js?v=9"></script><!-- etherpad plugin --> <script src="etherpad.js?v=9"></script><!-- etherpad plugin -->
<script src="prezi.js?v=6"></script><!-- prezi plugin --> <script src="prezi.js?v=6"></script><!-- prezi plugin -->
<script src="smileys.js?v=3"></script><!-- smiley images --> <script src="smileys.js?v=3"></script><!-- smiley images -->
...@@ -51,33 +52,36 @@ ...@@ -51,33 +52,36 @@
<script src="analytics.js?v=1"></script><!-- google analytics plugin --> <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<script src="rtp_sts.js?v=5"></script><!-- RTP stats processing --> <script src="rtp_sts.js?v=5"></script><!-- RTP stats processing -->
<script src="local_sts.js?v=2"></script><!-- Local stats processing --> <script src="local_sts.js?v=2"></script><!-- Local stats processing -->
<script src="videolayout.js?v=28"></script><!-- video ui --> <script src="videolayout.js?v=29"></script><!-- video ui -->
<script src="connectionquality.js?v=1"></script> <script src="connectionquality.js?v=1"></script>
<script src="toolbar.js?v=6"></script><!-- toolbar ui --> <script src="toolbar.js?v=6"></script><!-- toolbar ui -->
<script src="toolbar_toggler.js?v=2"></script> <script src="toolbar_toggler.js?v=2"></script>
<script src="canvas_util.js?v=1"></script><!-- canvas drawing utils --> <script src="canvas_util.js?v=1"></script><!-- canvas drawing utils -->
<script src="audio_levels.js?v=2"></script><!-- audio levels plugin --> <script src="audio_levels.js?v=2"></script><!-- audio levels plugin -->
<script src="media_stream.js?v=1"></script><!-- media stream --> <script src="media_stream.js?v=2"></script><!-- media stream -->
<script src="bottom_toolbar.js?v=5"></script><!-- media stream --> <script src="bottom_toolbar.js?v=6"></script><!-- media stream -->
<script src="roomname_generator.js?v=1"></script><!-- generator for random room names --> <script src="roomname_generator.js?v=1"></script><!-- generator for random room names -->
<script src="keyboard_shortcut.js?v=3"></script> <script src="keyboard_shortcut.js?v=3"></script>
<script src="tracking.js?v=1"></script><!-- tracking --> <script src="tracking.js?v=1"></script><!-- tracking -->
<script src="jitsipopover.js?v=3"></script> <script src="jitsipopover.js?v=3"></script>
<script src="message_handler.js?v=2"></script> <script src="message_handler.js?v=2"></script>
<script src="api_connector.js?v=2"></script> <script src="api_connector.js?v=2"></script>
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> <script src="settings_menu.js?v=1"></script>
<link rel="stylesheet" href="css/font.css?v=5"/> <script src="avatar.js?v=1"></script><!-- avatars -->
<link rel="stylesheet" href="css/font.css?v=6"/>
<link rel="stylesheet" href="css/toastr.css?v=1"> <link rel="stylesheet" href="css/toastr.css?v=1">
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=29"/> <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=30"/>
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=13" id="videolayout_default"/> <link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=14" id="videolayout_default"/>
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4"> <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
<link rel="stylesheet" href="css/modaldialog.css?v=3"> <link rel="stylesheet" href="css/modaldialog.css?v=3">
<link rel="stylesheet" href="css/popup_menu.css?v=4"> <link rel="stylesheet" href="css/popup_menu.css?v=4">
<link rel="stylesheet" href="css/popover.css?v=2"> <link rel="stylesheet" href="css/popover.css?v=2">
<link rel="stylesheet" href="css/jitsi_popover.css?v=2"> <link rel="stylesheet" href="css/jitsi_popover.css?v=2">
<link rel="stylesheet" href="css/contact_list.css?v=3"> <link rel="stylesheet" href="css/contact_list.css?v=4">
<link rel="stylesheet" href="css/chat.css?v=5"> <link rel="stylesheet" href="css/chat.css?v=5">
<link rel="stylesheet" href="css/welcome_page.css?v=2"> <link rel="stylesheet" href="css/welcome_page.css?v=2">
<link rel="stylesheet" href="css/settingsmenu.css?v=1">
<!-- <!--
Link used for inline installation of chrome desktop streaming extension, Link used for inline installation of chrome desktop streaming extension,
is updated automatically from the code with the value defined in config.js --> is updated automatically from the code with the value defined in config.js -->
...@@ -237,6 +241,10 @@ ...@@ -237,6 +241,10 @@
<i class="icon-telephone"></i></a> <i class="icon-telephone"></i></a>
</span> </span>
<div class="header_button_separator"></div> <div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" onclick='PanelToggler.toggleSettingsMenu();'>
<i id="settingsButton" class="icon-settings"></i>
</a>
<div class="header_button_separator"></div>
<span id="hangup"> <span id="hangup">
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" onclick='hangup();'> <a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" onclick='hangup();'>
<i class="icon-hangup" style="color:#ff0000;font-size: 1.4em;"></i> <i class="icon-hangup" style="color:#ff0000;font-size: 1.4em;"></i>
...@@ -263,6 +271,7 @@ ...@@ -263,6 +271,7 @@
<a target="_new"><div class="watermark leftwatermark"></div></a> <a target="_new"><div class="watermark leftwatermark"></div></a>
<a target="_new"><div class="watermark rightwatermark"></div></a> <a target="_new"><div class="watermark rightwatermark"></div></a>
<a class="poweredby" href="http://jitsi.org" target="_new" >powered by jitsi.org</a> <a class="poweredby" href="http://jitsi.org" target="_new" >powered by jitsi.org</a>
<img id="activeSpeakerAvatar" src=""/>
<video id="largeVideo" autoplay oncontextmenu="return false;"></video> <video id="largeVideo" autoplay oncontextmenu="return false;"></video>
</div> </div>
<div id="remoteVideos"> <div id="remoteVideos">
...@@ -306,7 +315,7 @@ ...@@ -306,7 +315,7 @@
</span> </span>
</span> </span>
</div> </div>
<div id="chatspace"> <div id="chatspace" class="right-panel">
<div id="nickname"> <div id="nickname">
Enter a nickname in the box below Enter a nickname in the box below
<form> <form>
...@@ -324,11 +333,19 @@ ...@@ -324,11 +333,19 @@
</div> </div>
</div> </div>
</div> </div>
<div id="contactlist"> <div id="contactlist" class="right-panel">
<ul> <ul>
<li class="title"><i class="icon-contact-list"></i> CONTACT LIST</li> <li class="title"><i class="icon-contact-list"></i> CONTACT LIST</li>
</ul> </ul>
</div> </div>
<div id="settingsmenu" class="right-panel">
<div class="icon-settings"> SETTINGS</div>
<img id="avatar" src="//www.gravatar.com/avatar/00000000000000000000000000000000?d=mm&size=30"/> <!-- BAO -->
<div class="arrow-up"></div>
<input type="text" id="setDisplayName" placeholder="Name">
<input type="text" id="setEmail" placeholder="E-Mail">
<button onclick="SettingsMenu.update()" id="updateSettings">Update</button>
</div>
<a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a> <a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
</div> </div>
</body> </body>
......
...@@ -6,11 +6,13 @@ var interfaceConfig = { ...@@ -6,11 +6,13 @@ var interfaceConfig = {
TOOLBAR_TIMEOUT: 4000, TOOLBAR_TIMEOUT: 4000,
DEFAULT_REMOTE_DISPLAY_NAME: "Change Me", DEFAULT_REMOTE_DISPLAY_NAME: "Change Me",
DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME: "Speaker", DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME: "Speaker",
DEFAULT_LOCAL_DISPLAY_NAME: "me",
SHOW_JITSI_WATERMARK: false, SHOW_JITSI_WATERMARK: false,
JITSI_WATERMARK_LINK: "", JITSI_WATERMARK_LINK: "",
SHOW_BRAND_WATERMARK: false, SHOW_BRAND_WATERMARK: false,
BRAND_WATERMARK_LINK: "", BRAND_WATERMARK_LINK: "",
SHOW_POWERED_BY: false, SHOW_POWERED_BY: false,
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true, GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
APP_NAME: "Openfire Meetings" APP_NAME: "Openfire Meetings",
ACTIVE_SPEAKER_AVATAR_SIZE: 100
}; };
...@@ -44,7 +44,7 @@ public class JigasiPlugin ...@@ -44,7 +44,7 @@ public class JigasiPlugin
this.pluginDirectory = pluginDirectory; this.pluginDirectory = pluginDirectory;
ComponentManager componentManager = ComponentManagerFactory.getComponentManager(); ComponentManager componentManager = ComponentManagerFactory.getComponentManager();
String subdomain = "call-control"; String subdomain = "ofmeet-call-control";
CallControlComponent component = new CallControlComponent(pluginDirectory); CallControlComponent component = new CallControlComponent(pluginDirectory);
boolean added = false; boolean added = false;
......
...@@ -9,6 +9,7 @@ package org.jitsi.videobridge.openfire; ...@@ -9,6 +9,7 @@ package org.jitsi.videobridge.openfire;
import org.jivesoftware.util.*; import org.jivesoftware.util.*;
import org.jivesoftware.openfire.*; import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.vcard.VCardManager;
import org.slf4j.*; import org.slf4j.*;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -25,6 +26,8 @@ import java.util.*; ...@@ -25,6 +26,8 @@ import java.util.*;
import java.text.*; import java.text.*;
import java.security.Principal; import java.security.Principal;
import org.dom4j.*;
public class Config extends HttpServlet public class Config extends HttpServlet
{ {
...@@ -38,12 +41,27 @@ public class Config extends HttpServlet ...@@ -38,12 +41,27 @@ public class Config extends HttpServlet
String hostname = XMPPServer.getInstance().getServerInfo().getHostname(); String hostname = XMPPServer.getInstance().getServerInfo().getHostname();
String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain(); String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
String userName = "null"; String userName = "null";
String userAvatar = "null";
String securityEnabled = JiveGlobals.getProperty("ofmeet.security.enabled", "true"); String securityEnabled = JiveGlobals.getProperty("ofmeet.security.enabled", "true");
if ("true".equals(securityEnabled)) if ("true".equals(securityEnabled))
{ {
userName = request.getUserPrincipal().getName(); userName = request.getUserPrincipal().getName();
VCardManager vcardManager = VCardManager.getInstance();
Element vcard = vcardManager.getVCard(userName);
if (vcard != null)
{
Element photo = vcard.element("PHOTO");
if (photo != null)
{
String type = photo.element("TYPE").getText();
String binval = photo.element("BINVAL").getText();
userAvatar = "data:" + type + ";base64," + binval.replace("\n", "").replace("\r", "");;
}
}
} }
boolean nodejs = XMPPServer.getInstance().getPluginManager().getPlugin("nodejs") != null; boolean nodejs = XMPPServer.getInstance().getPluginManager().getPlugin("nodejs") != null;
...@@ -80,8 +98,8 @@ public class Config extends HttpServlet ...@@ -80,8 +98,8 @@ public class Config extends HttpServlet
out.println(" hosts: {"); out.println(" hosts: {");
out.println(" domain: '" + domain + "',"); out.println(" domain: '" + domain + "',");
out.println(" muc: 'conference." + domain + "',"); out.println(" muc: 'conference." + domain + "',");
out.println(" bridge: 'jitsi-videobridge." + domain + "',"); out.println(" bridge: 'ofmeet-jitsi-videobridge." + domain + "',");
out.println(" call_control: 'call-control." + domain + "',"); out.println(" call_control: 'ofmeet-call-control." + domain + "',");
out.println(" },"); out.println(" },");
out.println(" getroomnode: function (path)"); out.println(" getroomnode: function (path)");
out.println(" {"); out.println(" {");
...@@ -126,6 +144,7 @@ public class Config extends HttpServlet ...@@ -126,6 +144,7 @@ public class Config extends HttpServlet
out.println(" audioBandwidth: '" + audioBandwidth + "',"); out.println(" audioBandwidth: '" + audioBandwidth + "',");
out.println(" videoBandwidth: '" + videoBandwidth + "',"); out.println(" videoBandwidth: '" + videoBandwidth + "',");
out.println(" userName: '" + userName + "',"); out.println(" userName: '" + userName + "',");
out.println(" userAvatar: '" + userAvatar + "',");
out.println(" disablePrezi: true,"); out.println(" disablePrezi: true,");
out.println(" bosh: window.location.protocol + '//' + window.location.host + '/http-bind/'"); out.println(" bosh: window.location.protocol + '//' + window.location.host + '/http-bind/'");
out.println("}; "); out.println("}; ");
......
...@@ -186,7 +186,7 @@ public class PluginImpl ...@@ -186,7 +186,7 @@ public class PluginImpl
ComponentManager componentManager ComponentManager componentManager
= ComponentManagerFactory.getComponentManager(); = ComponentManagerFactory.getComponentManager();
String subdomain = ComponentImpl.SUBDOMAIN; String subdomain = "ofmeet-jitsi-videobridge"; //ComponentImpl.SUBDOMAIN;
PluginImpl.component = new ComponentImpl(); PluginImpl.component = new ComponentImpl();
boolean added = false; boolean added = false;
......
...@@ -56,7 +56,7 @@ public class OfMeetPlugin implements Plugin, ClusterEventListener { ...@@ -56,7 +56,7 @@ public class OfMeetPlugin implements Plugin, ClusterEventListener {
private PluginImpl jitsiPlugin; private PluginImpl jitsiPlugin;
private JigasiPlugin jigasiPlugin; private JigasiPlugin jigasiPlugin;
private PluginManager manager; private PluginManager manager;
private File pluginDirectory; public File pluginDirectory;
public String sipRegisterStatus = ""; public String sipRegisterStatus = "";
......
...@@ -462,7 +462,8 @@ ColibriFocus.prototype.createdConference = function (result) { ...@@ -462,7 +462,8 @@ ColibriFocus.prototype.createdConference = function (result) {
'a=rtpmap:100 VP8/90000\r\n' + 'a=rtpmap:100 VP8/90000\r\n' +
'a=rtcp-fb:100 ccm fir\r\n' + 'a=rtcp-fb:100 ccm fir\r\n' +
'a=rtcp-fb:100 nack\r\n' + 'a=rtcp-fb:100 nack\r\n' +
'a=rtcp-fb:100 goog-remb\r\n' + 'a=rtcp-fb:100 nack pli\r\n' +
(config.enableFirefoxSupport? "" : 'a=rtcp-fb:100 goog-remb\r\n') +
'a=rtpmap:116 red/90000\r\n' + 'a=rtpmap:116 red/90000\r\n' +
'a=rtpmap:117 ulpfec/90000\r\n' + 'a=rtpmap:117 ulpfec/90000\r\n' +
(config.useRtcpMux ? 'a=rtcp-mux\r\n' : '') + (config.useRtcpMux ? 'a=rtcp-mux\r\n' : '') +
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
try { try {
message = JSON.parse(event.data); message = JSON.parse(event.data);
} catch (e) {} } catch (e) {}
if (message && message.id && (player = PreziPlayer.players[message.id])){ if (message.id && (player = PreziPlayer.players[message.id])){
if (player.options.debug === true) { if (player.options.debug === true) {
if (console && console.log) console.log('received', message); if (console && console.log) console.log('received', message);
} }
......
...@@ -46,7 +46,7 @@ Strophe.addConnectionPlugin('rayo', ...@@ -46,7 +46,7 @@ Strophe.addConnectionPlugin('rayo',
console.info('Dial result ', result); console.info('Dial result ', result);
var resource = $(result).find('ref').attr('uri'); var resource = $(result).find('ref').attr('uri');
self.call_resource = resource.substr('xmpp:'.length); self.call_resource = resource.substr('xmpp:'.length); // BAO
console.info( console.info(
"Received call resource: " + self.call_resource); "Received call resource: " + self.call_resource);
}, },
......
...@@ -141,12 +141,28 @@ if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) { ...@@ -141,12 +141,28 @@ if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
TraceablePeerConnection.prototype.addStream = function (stream) { TraceablePeerConnection.prototype.addStream = function (stream) {
this.trace('addStream', stream.id); this.trace('addStream', stream.id);
simulcast.resetSender(); simulcast.resetSender();
this.peerconnection.addStream(stream); try
{
this.peerconnection.addStream(stream);
}
catch (e)
{
console.error(e);
return;
}
}; };
TraceablePeerConnection.prototype.removeStream = function (stream) { TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
this.trace('removeStream', stream.id); this.trace('removeStream', stream.id);
simulcast.resetSender(); simulcast.resetSender();
if(stopStreams) {
stream.getAudioTracks().forEach(function (track) {
track.stop();
});
stream.getVideoTracks().forEach(function (track) {
track.stop();
});
}
this.peerconnection.removeStream(stream); this.peerconnection.removeStream(stream);
}; };
...@@ -477,6 +493,11 @@ TraceablePeerConnection.prototype.addIceCandidate = function (candidate, success ...@@ -477,6 +493,11 @@ TraceablePeerConnection.prototype.addIceCandidate = function (candidate, success
TraceablePeerConnection.prototype.getStats = function(callback, errback) { TraceablePeerConnection.prototype.getStats = function(callback, errback) {
if (navigator.mozGetUserMedia) { if (navigator.mozGetUserMedia) {
// ignore for now... // ignore for now...
if(!errback)
errback = function () {
}
this.peerconnection.getStats(null,callback,errback);
} else { } else {
this.peerconnection.getStats(callback); this.peerconnection.getStats(callback);
} }
...@@ -497,7 +518,40 @@ function setupRTC() { ...@@ -497,7 +518,40 @@ function setupRTC() {
element[0].mozSrcObject = stream; element[0].mozSrcObject = stream;
element[0].play(); element[0].play();
}, },
pc_constraints: {} pc_constraints: {},
getLocalSSRC: function (session, callback) {
session.peerconnection.getStats(function (s) {
var ssrcs = {};
s.forEach(function (item) {
if (item.type == "outboundrtp" && !item.isRemote)
{
ssrcs[item.id.split('_')[2]] = item.ssrc;
}
});
session.localStreamsSSRC = {
"audio": ssrcs.audio,//for stable 0
"video": ssrcs.video// for stable 1
};
callback(session.localStreamsSSRC);
},
function () {
callback(null);
});
},
getStreamID: function (stream) {
var tracks = stream.getVideoTracks();
if(!tracks || tracks.length == 0)
{
tracks = stream.getAudioTracks();
}
return tracks[0].id.replace(/[\{,\}]/g,"");
},
getVideoSrc: function (element) {
return element.mozSrcObject;
},
setVideoSrc: function (element, src) {
element.mozSrcObject = src;
}
}; };
if (!MediaStream.prototype.getVideoTracks) if (!MediaStream.prototype.getVideoTracks)
MediaStream.prototype.getVideoTracks = function () { return []; }; MediaStream.prototype.getVideoTracks = function () { return []; };
...@@ -516,7 +570,19 @@ function setupRTC() { ...@@ -516,7 +570,19 @@ function setupRTC() {
element.attr('src', webkitURL.createObjectURL(stream)); element.attr('src', webkitURL.createObjectURL(stream));
}, },
// DTLS should now be enabled by default but.. // DTLS should now be enabled by default but..
pc_constraints: {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]} pc_constraints: {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]},
getLocalSSRC: function (session, callback) {
callback(null);
},
getStreamID: function (stream) {
return stream.id;
},
getVideoSrc: function (element) {
return element.getAttribute("src");
},
setVideoSrc: function (element, src) {
element.setAttribute("src", src);
}
}; };
if (navigator.userAgent.indexOf('Android') != -1) { if (navigator.userAgent.indexOf('Android') != -1) {
RTC.pc_constraints = {}; // disable DTLS on Android RTC.pc_constraints = {}; // disable DTLS on Android
......
...@@ -84,7 +84,9 @@ Strophe.addConnectionPlugin('jingle', { ...@@ -84,7 +84,9 @@ Strophe.addConnectionPlugin('jingle', {
case 'session-initiate': case 'session-initiate':
sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection); sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection);
// configure session // configure session
if (this.localAudio) {
//in firefox we have only one stream object
if (this.localAudio != this.localVideo) {
sess.localStreams.push(this.localAudio); sess.localStreams.push(this.localAudio);
} }
if (this.localVideo) { if (this.localVideo) {
...@@ -169,7 +171,9 @@ Strophe.addConnectionPlugin('jingle', { ...@@ -169,7 +171,9 @@ Strophe.addConnectionPlugin('jingle', {
Math.random().toString(36).substr(2, 12), // random string Math.random().toString(36).substr(2, 12), // random string
this.connection); this.connection);
// configure session // configure session
if (this.localAudio) {
//in firefox we have only one stream
if (this.localAudio != this.localVideo) {
sess.localStreams.push(this.localAudio); sess.localStreams.push(this.localAudio);
} }
if (this.localVideo) { if (this.localVideo) {
......
...@@ -194,7 +194,8 @@ SDP.prototype.removeMediaLines = function(mediaindex, prefix) { ...@@ -194,7 +194,8 @@ SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
} }
// add content's to a jingle element // add content's to a jingle element
SDP.prototype.toJingle = function (elem, thecreator) { SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
// console.log("SSRC" + ssrcs["audio"] + " - " + ssrcs["video"]);
var i, j, k, mline, ssrc, rtpmap, tmp, line, lines; var i, j, k, mline, ssrc, rtpmap, tmp, line, lines;
var self = this; var self = this;
// new bundle plan // new bundle plan
...@@ -221,7 +222,12 @@ SDP.prototype.toJingle = function (elem, thecreator) { ...@@ -221,7 +222,12 @@ SDP.prototype.toJingle = function (elem, thecreator) {
if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) { if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) {
ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first
} else { } else {
ssrc = false; if(ssrcs && ssrcs[mline.media])
{
ssrc = ssrcs[mline.media];
}
else
ssrc = false;
} }
elem.c('content', {creator: thecreator, name: mline.media}); elem.c('content', {creator: thecreator, name: mline.media});
...@@ -267,25 +273,60 @@ SDP.prototype.toJingle = function (elem, thecreator) { ...@@ -267,25 +273,60 @@ SDP.prototype.toJingle = function (elem, thecreator) {
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' }); elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
// FIXME: group by ssrc and support multiple different ssrcs // FIXME: group by ssrc and support multiple different ssrcs
var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:'); var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:');
ssrclines.forEach(function(line) { if(ssrclines.length > 0) {
idx = line.indexOf(' '); ssrclines.forEach(function (line) {
var linessrc = line.substr(0, idx).substr(7); idx = line.indexOf(' ');
if (linessrc != ssrc) { var linessrc = line.substr(0, idx).substr(7);
if (linessrc != ssrc) {
elem.up();
ssrc = linessrc;
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
}
var kv = line.substr(idx + 1);
elem.c('parameter');
if (kv.indexOf(':') == -1) {
elem.attrs({ name: kv });
} else {
elem.attrs({ name: kv.split(':', 2)[0] });
elem.attrs({ value: kv.split(':', 2)[1] });
}
elem.up(); elem.up();
ssrc = linessrc; });
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' }); elem.up();
} }
var kv = line.substr(idx + 1); else
{
elem.up();
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
elem.c('parameter'); elem.c('parameter');
if (kv.indexOf(':') == -1) { elem.attrs({name: "cname", value:Math.random().toString(36).substring(7)});
elem.attrs({ name: kv });
} else {
elem.attrs({ name: kv.split(':', 2)[0] });
elem.attrs({ value: kv.split(':', 2)[1] });
}
elem.up(); elem.up();
}); var msid = null;
elem.up(); if(mline.media == "audio")
{
msid = connection.jingle.localAudio.getAudioTracks()[0].id;
}
else
{
msid = connection.jingle.localVideo.getVideoTracks()[0].id;
}
if(msid != null)
{
msid = msid.replace(/[\{,\}]/g,"");
elem.c('parameter');
elem.attrs({name: "msid", value:msid});
elem.up();
elem.c('parameter');
elem.attrs({name: "mslabel", value:msid});
elem.up();
elem.c('parameter');
elem.attrs({name: "label", value:msid});
elem.up();
elem.up();
}
}
// XEP-0339 handle ssrc-group attributes // XEP-0339 handle ssrc-group attributes
var ssrc_group_lines = SDPUtil.find_lines(this.media[i], 'a=ssrc-group:'); var ssrc_group_lines = SDPUtil.find_lines(this.media[i], 'a=ssrc-group:');
......
...@@ -36,6 +36,7 @@ function JingleSession(me, sid, connection) { ...@@ -36,6 +36,7 @@ function JingleSession(me, sid, connection) {
this.reason = null; this.reason = null;
this.wait = true; this.wait = true;
this.localStreamsSSRC = null;
} }
JingleSession.prototype.initiate = function (peerjid, isInitiator) { JingleSession.prototype.initiate = function (peerjid, isInitiator) {
...@@ -64,6 +65,7 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) { ...@@ -64,6 +65,7 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
}; };
this.peerconnection.onaddstream = function (event) { this.peerconnection.onaddstream = function (event) {
self.remoteStreams.push(event.stream); self.remoteStreams.push(event.stream);
console.log("REMOTE STREAM ADDED: " + event.stream + " - " + event.stream.id);
$(document).trigger('remotestreamadded.jingle', [event, self.sid]); $(document).trigger('remotestreamadded.jingle', [event, self.sid]);
}; };
this.peerconnection.onremovestream = function (event) { this.peerconnection.onremovestream = function (event) {
...@@ -128,7 +130,7 @@ JingleSession.prototype.accept = function () { ...@@ -128,7 +130,7 @@ JingleSession.prototype.accept = function () {
initiator: this.initiator, initiator: this.initiator,
responder: this.responder, responder: this.responder,
sid: this.sid }); sid: this.sid });
prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder'); prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC);
this.connection.sendIQ(accept, this.connection.sendIQ(accept,
function () { function () {
var ack = {}; var ack = {};
...@@ -219,10 +221,10 @@ JingleSession.prototype.sendIceCandidate = function (candidate) { ...@@ -219,10 +221,10 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
}, 20); }, 20);
} }
this.drip_container.push(event.candidate); this.drip_container.push(candidate);
return; return;
} else { } else {
self.sendIceCandidate([event.candidate]); self.sendIceCandidate([candidate]);
} }
} }
} else { } else {
...@@ -236,25 +238,43 @@ JingleSession.prototype.sendIceCandidate = function (candidate) { ...@@ -236,25 +238,43 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
initiator: this.initiator, initiator: this.initiator,
sid: this.sid}); sid: this.sid});
this.localSDP = new SDP(this.peerconnection.localDescription.sdp); this.localSDP = new SDP(this.peerconnection.localDescription.sdp);
this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder'); var self = this;
this.connection.sendIQ(init, var sendJingle = function (ssrc) {
function () { if(!ssrc)
//console.log('session initiate ack'); ssrc = {};
var ack = {}; self.localSDP.toJingle(init, self.initiator == self.me ? 'initiator' : 'responder', ssrc);
ack.source = 'offer'; self.connection.sendIQ(init,
$(document).trigger('ack.jingle', [self.sid, ack]); function () {
}, //console.log('session initiate ack');
function (stanza) { var ack = {};
self.state = 'error'; ack.source = 'offer';
self.peerconnection.close(); $(document).trigger('ack.jingle', [self.sid, ack]);
var error = ($(stanza).find('error').length) ? { },
code: $(stanza).find('error').attr('code'), function (stanza) {
reason: $(stanza).find('error :first')[0].tagName, self.state = 'error';
}:{}; self.peerconnection.close();
error.source = 'offer'; var error = ($(stanza).find('error').length) ? {
$(document).trigger('error.jingle', [self.sid, error]); code: $(stanza).find('error').attr('code'),
}, reason: $(stanza).find('error :first')[0].tagName,
10000); }:{};
error.source = 'offer';
$(document).trigger('error.jingle', [self.sid, error]);
},
10000);
}
RTC.getLocalSSRC(this, function (ssrcs) {
if(ssrcs)
{
sendJingle(ssrcs);
$(document).trigger("setLocalDescription.jingle", [self.sid]);
}
else
{
sendJingle();
}
});
} }
this.lasticecandidate = true; this.lasticecandidate = true;
console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate); console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate);
...@@ -275,11 +295,12 @@ JingleSession.prototype.sendIceCandidates = function (candidates) { ...@@ -275,11 +295,12 @@ JingleSession.prototype.sendIceCandidates = function (candidates) {
sid: this.sid}); sid: this.sid});
for (var mid = 0; mid < this.localSDP.media.length; mid++) { for (var mid = 0; mid < this.localSDP.media.length; mid++) {
var cands = candidates.filter(function (el) { return el.sdpMLineIndex == mid; }); var cands = candidates.filter(function (el) { return el.sdpMLineIndex == mid; });
var mline = SDPUtil.parse_mline(this.localSDP.media[mid].split('\r\n')[0]);
if (cands.length > 0) { if (cands.length > 0) {
var ice = SDPUtil.iceparams(this.localSDP.media[mid], this.localSDP.session); var ice = SDPUtil.iceparams(this.localSDP.media[mid], this.localSDP.session);
ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1'; ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
cand.c('content', {creator: this.initiator == this.me ? 'initiator' : 'responder', cand.c('content', {creator: this.initiator == this.me ? 'initiator' : 'responder',
name: cands[0].sdpMid name: (cands[0].sdpMid? cands[0].sdpMid : mline.media)
}).c('transport', ice); }).c('transport', ice);
for (var i = 0; i < cands.length; i++) { for (var i = 0; i < cands.length; i++) {
cand.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up(); cand.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up();
...@@ -338,14 +359,14 @@ JingleSession.prototype.createdOffer = function (sdp) { ...@@ -338,14 +359,14 @@ JingleSession.prototype.createdOffer = function (sdp) {
var self = this; var self = this;
this.localSDP = new SDP(sdp.sdp); this.localSDP = new SDP(sdp.sdp);
//this.localSDP.mangle(); //this.localSDP.mangle();
if (this.usetrickle) { var sendJingle = function () {
var init = $iq({to: this.peerjid, var init = $iq({to: this.peerjid,
type: 'set'}) type: 'set'})
.c('jingle', {xmlns: 'urn:xmpp:jingle:1', .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
action: 'session-initiate', action: 'session-initiate',
initiator: this.initiator, initiator: this.initiator,
sid: this.sid}); sid: this.sid});
this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder'); this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC);
this.connection.sendIQ(init, this.connection.sendIQ(init,
function () { function () {
var ack = {}; var ack = {};
...@@ -367,7 +388,16 @@ JingleSession.prototype.createdOffer = function (sdp) { ...@@ -367,7 +388,16 @@ JingleSession.prototype.createdOffer = function (sdp) {
sdp.sdp = this.localSDP.raw; sdp.sdp = this.localSDP.raw;
this.peerconnection.setLocalDescription(sdp, this.peerconnection.setLocalDescription(sdp,
function () { function () {
$(document).trigger('setLocalDescription.jingle', [self.sid]); if(this.usetrickle)
{
RTC.getLocalSSRC(function(ssrc)
{
sendJingle(ssrc);
$(document).trigger('setLocalDescription.jingle', [self.sid]);
});
}
else
$(document).trigger('setLocalDescription.jingle', [self.sid]);
//console.log('setLocalDescription success'); //console.log('setLocalDescription success');
}, },
function (e) { function (e) {
...@@ -558,33 +588,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) { ...@@ -558,33 +588,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
//this.localSDP.mangle(); //this.localSDP.mangle();
this.usepranswer = provisional === true; this.usepranswer = provisional === true;
if (this.usetrickle) { if (this.usetrickle) {
if (!this.usepranswer) { if (this.usepranswer) {
var accept = $iq({to: this.peerjid,
type: 'set'})
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
action: 'session-accept',
initiator: this.initiator,
responder: this.responder,
sid: this.sid });
var publicLocalDesc = simulcast.reverseTransformLocalDescription(sdp);
var publicLocalSDP = new SDP(publicLocalDesc.sdp);
publicLocalSDP.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder');
this.connection.sendIQ(accept,
function () {
var ack = {};
ack.source = 'answer';
$(document).trigger('ack.jingle', [self.sid, ack]);
},
function (stanza) {
var error = ($(stanza).find('error').length) ? {
code: $(stanza).find('error').attr('code'),
reason: $(stanza).find('error :first')[0].tagName,
}:{};
error.source = 'answer';
$(document).trigger('error.jingle', [self.sid, error]);
},
10000);
} else {
sdp.type = 'pranswer'; sdp.type = 'pranswer';
for (var i = 0; i < this.localSDP.media.length; i++) { for (var i = 0; i < this.localSDP.media.length; i++) {
this.localSDP.media[i] = this.localSDP.media[i].replace('a=sendrecv\r\n', 'a=inactive\r\n'); this.localSDP.media[i] = this.localSDP.media[i].replace('a=sendrecv\r\n', 'a=inactive\r\n');
...@@ -592,11 +596,48 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) { ...@@ -592,11 +596,48 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
this.localSDP.raw = this.localSDP.session + '\r\n' + this.localSDP.media.join(''); this.localSDP.raw = this.localSDP.session + '\r\n' + this.localSDP.media.join('');
} }
} }
var self = this;
var sendJingle = function (ssrcs) {
var accept = $iq({to: self.peerjid,
type: 'set'})
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
action: 'session-accept',
initiator: self.initiator,
responder: self.responder,
sid: self.sid });
var publicLocalDesc = simulcast.reverseTransformLocalDescription(sdp);
var publicLocalSDP = new SDP(publicLocalDesc.sdp);
publicLocalSDP.toJingle(accept, self.initiator == self.me ? 'initiator' : 'responder', ssrcs);
this.connection.sendIQ(accept,
function () {
var ack = {};
ack.source = 'answer';
$(document).trigger('ack.jingle', [self.sid, ack]);
},
function (stanza) {
var error = ($(stanza).find('error').length) ? {
code: $(stanza).find('error').attr('code'),
reason: $(stanza).find('error :first')[0].tagName,
}:{};
error.source = 'answer';
$(document).trigger('error.jingle', [self.sid, error]);
},
10000);
}
sdp.sdp = this.localSDP.raw; sdp.sdp = this.localSDP.raw;
this.peerconnection.setLocalDescription(sdp, this.peerconnection.setLocalDescription(sdp,
function () { function () {
$(document).trigger('setLocalDescription.jingle', [self.sid]);
//console.log('setLocalDescription success'); //console.log('setLocalDescription success');
if (self.usetrickle && !self.usepranswer) {
RTC.getLocalSSRC(self, function (ssrc) {
sendJingle(ssrc);
$(document).trigger('setLocalDescription.jingle', [self.sid]);
});
}
else
$(document).trigger('setLocalDescription.jingle', [self.sid]);
}, },
function (e) { function (e) {
console.error('setLocalDescription failed', e); console.error('setLocalDescription failed', e);
......
...@@ -82,14 +82,17 @@ SessionBase.prototype.switchStreams = function (new_stream, oldStream, success_c ...@@ -82,14 +82,17 @@ SessionBase.prototype.switchStreams = function (new_stream, oldStream, success_c
if(self.peerconnection.localDescription) { if(self.peerconnection.localDescription) {
oldSdp = new SDP(self.peerconnection.localDescription.sdp); oldSdp = new SDP(self.peerconnection.localDescription.sdp);
} }
self.peerconnection.removeStream(oldStream); self.peerconnection.removeStream(oldStream, true);
self.peerconnection.addStream(new_stream); self.peerconnection.addStream(new_stream);
} }
self.connection.jingle.localVideo = new_stream; self.connection.jingle.localVideo = new_stream;
self.connection.jingle.localStreams = []; self.connection.jingle.localStreams = [];
self.connection.jingle.localStreams.push(self.connection.jingle.localAudio);
//in firefox we have only one stream object
if(self.connection.jingle.localAudio != self.connection.jingle.localVideo)
self.connection.jingle.localStreams.push(self.connection.jingle.localAudio);
self.connection.jingle.localStreams.push(self.connection.jingle.localVideo); self.connection.jingle.localStreams.push(self.connection.jingle.localVideo);
// Conference is not active // Conference is not active
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -16,15 +16,17 @@ var MediaStream = (function() { ...@@ -16,15 +16,17 @@ var MediaStream = (function() {
* @constructor * @constructor
*/ */
function MediaStreamProto(data, sid, ssrc) { function MediaStreamProto(data, sid, ssrc) {
this.VIDEO_TYPE = "Video";
this.AUDIO_TYPE = "Audio";
this.stream = data.stream; this.stream = data.stream;
this.peerjid = data.peerjid; this.peerjid = data.peerjid;
this.ssrc = ssrc; this.ssrc = ssrc;
this.session = connection.jingle.sessions[sid]; this.session = connection.jingle.sessions[sid];
this.type = (this.stream.getVideoTracks().length > 0) this.type = (this.stream.getVideoTracks().length > 0)
? this.VIDEO_TYPE : this.AUDIO_TYPE; ? MediaStream.VIDEO_TYPE : MediaStream.AUDIO_TYPE;
this.muted = false;
} }
return MediaStreamProto; return MediaStreamProto;
})(); })();
\ No newline at end of file
MediaStream.VIDEO_TYPE = 'Video';
MediaStream.AUDIO_TYPE = 'Audio';
\ No newline at end of file
/* global $, $iq, config, connection, Etherpad, hangUp, roomName, Strophe,
Toolbar, Util, VideoLayout */
/**
* Contains logic responsible for enabling/disabling functionality available
* only to moderator users.
*/
var Moderator = (function (my) {
var getNextTimeout = Util.createExpBackoffTimer(1000);
var getNextErrorTimeout = Util.createExpBackoffTimer(1000);
my.isModerator = function () {
return connection.emuc.isModerator();
};
my.onModeratorStatusChanged = function (isModerator) {
Toolbar.showSipCallButton(isModerator);
Toolbar.showRecordingButton(
isModerator); //&&
// FIXME:
// Recording visible if
// there are at least 2(+ 1 focus) participants
//Object.keys(connection.emuc.members).length >= 3);
if (isModerator && config.etherpad_base) {
Etherpad.init();
}
$(document).trigger('local.role.moderator', [isModerator]);
};
my.init = function () {
$(document).bind(
'role.changed.muc',
function (event, jid, info, pres) {
console.info(
"Role changed for " + jid + ", new role: " + info.role);
VideoLayout.showModeratorIndicator();
}
);
$(document).bind(
'local.role.changed.muc',
function (event, jid, info, pres) {
console.info("My role changed, new role: " + info.role);
VideoLayout.showModeratorIndicator();
Moderator.onModeratorStatusChanged(Moderator.isModerator());
}
);
$(document).bind(
'left.muc',
function (event, jid) {
console.info("Someone left is it focus ? " + jid);
var resource = Strophe.getResourceFromJid(jid);
if (resource === 'focus') {
console.info(
"Focus has left the room - leaving conference");
//hangUp();
// We'd rather reload to have everything re-initialized
// FIXME: show some message before reload
location.reload();
}
}
);
};
my.createConferenceIq = function () {
var elem = $iq({to: config.hosts.focus, type: 'set'});
elem.c('conference', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName
});
if (config.channelLastN !== undefined)
{
elem.c(
'property',
{ name: 'channelLastN', value: config.channelLastN})
.up();
}
if (config.adaptiveLastN !== undefined)
{
elem.c(
'property',
{ name: 'adaptiveLastN', value: config.adaptiveLastN})
.up();
}
if (config.adaptiveSimulcast !== undefined)
{
elem.c(
'property',
{ name: 'adaptiveSimulcast', value: config.adaptiveSimulcast})
.up();
}
elem.up();
return elem;
};
// FIXME: we need to show the fact that we're waiting for the focus
// to the user(or that focus is not available)
my.allocateConferenceFocus = function (roomName, callback) {
var iq = Moderator.createConferenceIq();
connection.sendIQ(
iq,
function (result) {
if ('true' === $(result).find('conference').attr('ready')) {
// Reset both timers
getNextTimeout(true);
getNextErrorTimeout(true);
callback();
} else {
var waitMs = getNextTimeout();
console.info("Waiting for the focus... " + waitMs);
// Reset error timeout
getNextErrorTimeout(true);
window.setTimeout(
function () {
Moderator.allocateConferenceFocus(
roomName, callback);
}, waitMs);
}
},
function (error) {
var waitMs = getNextErrorTimeout();
console.error("Focus error, retry after " + waitMs, error);
// Reset response timeout
getNextTimeout(true);
window.setTimeout(
function () {
Moderator.allocateConferenceFocus(roomName, callback);
}, waitMs);
}
);
};
return my;
}(Moderator || {}));
...@@ -111,7 +111,7 @@ Strophe.addConnectionPlugin('emuc', { ...@@ -111,7 +111,7 @@ Strophe.addConnectionPlugin('emuc', {
var create = $iq({type: 'set', to: this.roomjid}) var create = $iq({type: 'set', to: this.roomjid})
.c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'}) .c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
.c('x', {xmlns: 'jabber:x:data', type: 'submit'}); .c('x', {xmlns: 'jabber:x:data', type: 'submit'});
this.connection.send(create); // fire away this.connection.sendIQ(create); // fire away
} }
// Parse roles. // Parse roles.
...@@ -335,6 +335,14 @@ Strophe.addConnectionPlugin('emuc', { ...@@ -335,6 +335,14 @@ Strophe.addConnectionPlugin('emuc', {
pres.c('bridgeIsDown').up(); pres.c('bridgeIsDown').up();
} }
if(this.presMap['email']) {
pres.c('email').t(this.presMap['email']).up();
}
if(this.presMap['userId']) {
pres.c('userId').t(this.presMap['userId']).up();
}
if (this.presMap['displayName']) { if (this.presMap['displayName']) {
// XEP-0172 // XEP-0172
pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'}) pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'})
...@@ -456,5 +464,11 @@ Strophe.addConnectionPlugin('emuc', { ...@@ -456,5 +464,11 @@ Strophe.addConnectionPlugin('emuc', {
}, },
addBridgeIsDownToPresence: function() { addBridgeIsDownToPresence: function() {
this.presMap['bridgeIsDown'] = true; this.presMap['bridgeIsDown'] = true;
},
addEmailToPresence: function(email) {
this.presMap['email'] = email;
},
addUserIdToPresence: function(userId) {
this.presMap['userId'] = userId;
} }
}); });
...@@ -79,7 +79,7 @@ Strophe.addConnectionPlugin('ofmuc', { ...@@ -79,7 +79,7 @@ Strophe.addConnectionPlugin('ofmuc', {
var type = pres.getAttribute('type'); var type = pres.getAttribute('type');
if (type != null) { if (type != null) {
return true; return true;
} }
if (!this.roomJid || Strophe.getBareJidFromJid(from) != this.roomJid) return true; if (!this.roomJid || Strophe.getBareJidFromJid(from) != this.roomJid) return true;
...@@ -95,6 +95,11 @@ Strophe.addConnectionPlugin('ofmuc', { ...@@ -95,6 +95,11 @@ Strophe.addConnectionPlugin('ofmuc', {
} else if (this.members[from] === undefined) { } else if (this.members[from] === undefined) {
this.members[from] = member; this.members[from] = member;
if (config.userAvatar && config.userAvatar != "null")
{
this.avatarShare(config.userAvatar);
}
if (this.sharePDF) if (this.sharePDF)
{ {
...@@ -139,6 +144,12 @@ Strophe.addConnectionPlugin('ofmuc', { ...@@ -139,6 +144,12 @@ Strophe.addConnectionPlugin('ofmuc', {
that.handlePdfShare(action, url); that.handlePdfShare(action, url);
}); });
$(msg).find('avatarshare').each(function()
{
that.members[from].avatar = $(this).text();
Avatar.setUserAvatar(from);
});
return true; return true;
}, },
...@@ -180,7 +191,7 @@ Strophe.addConnectionPlugin('ofmuc', { ...@@ -180,7 +191,7 @@ Strophe.addConnectionPlugin('ofmuc', {
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
console.log("onRayo callid", callId, jid); //console.log("onRayo callid", callId, jid);
if (jid) if (jid)
{ {
...@@ -201,7 +212,7 @@ Strophe.addConnectionPlugin('ofmuc', { ...@@ -201,7 +212,7 @@ Strophe.addConnectionPlugin('ofmuc', {
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
console.log("onRayo callid", callId, jid); //console.log("onRayo callid", callId, jid);
if (jid) if (jid)
{ {
...@@ -266,6 +277,12 @@ Strophe.addConnectionPlugin('ofmuc', { ...@@ -266,6 +277,12 @@ Strophe.addConnectionPlugin('ofmuc', {
this.connection.send(msg); this.connection.send(msg);
}, },
avatarShare: function(avatar) {
//console.log("ofmuc.avatarShare", avatar)
var msg = $msg({to: this.roomJid, type: 'groupchat'});
msg.c('avatarshare', {xmlns: 'http://igniterealtime.org/protocol/avatarshare'}).t(avatar).up();
this.connection.send(msg);
},
pdfStart: function(url) { pdfStart: function(url) {
//console.log("pdfStart", url); //console.log("pdfStart", url);
......
/* global $, $iq, config, connection, focusJid, messageHandler, Moderator,
Toolbar, Util */
var Recording = (function (my) {
var recordingToken = null;
var recordingEnabled;
my.setRecordingToken = function (token) {
recordingToken = token;
};
// Sends a COLIBRI message which enables or disables (according to 'state')
// the recording on the bridge. Waits for the result IQ and calls 'callback'
// with the new recording state, according to the IQ.
my.setRecording = function (state, token, callback) {
var self = this;
var elem = $iq({to: focusJid, type: 'set'});
elem.c('conference', {
xmlns: 'http://jitsi.org/protocol/colibri'
});
elem.c('recording', {state: state, token: token});
elem.up();
connection.sendIQ(elem,
function (result) {
console.log('Set recording "', state, '". Result:', result);
var recordingElem = $(result).find('>conference>recording');
var newState = ('true' === recordingElem.attr('state'));
recordingEnabled = newState;
callback(newState);
},
function (error) {
console.warn(error);
}
);
};
my.toggleRecording = function () {
if (!Moderator.isModerator()) {
console.log(
'non-focus, or conference not yet organized:' +
' not enabling recording');
return;
}
if (!recordingToken)
{
messageHandler.openTwoButtonDialog(null,
'<h2>Enter recording token</h2>' +
'<input id="recordingToken" type="text" placeholder="token" autofocus>',
false,
"Save",
function (e, v, m, f) {
if (v) {
var token = document.getElementById('recordingToken');
if (token.value) {
my.setRecordingToken(
Util.escapeHtml(token.value));
my.toggleRecording();
}
}
},
function (event) {
document.getElementById('recordingToken').focus();
}
);
return;
}
var oldState = recordingEnabled;
Toolbar.setRecordingButtonState(!oldState);
my.setRecording(!oldState,
recordingToken,
function (state) {
console.log("New recording state: ", state);
if (state === oldState)
{
// FIXME: new focus:
// this will not work when moderator changes
// during active session. Then it will assume that
// recording status has changed to true, but it might have
// been already true(and we only received actual status from
// the focus).
//
// SO we start with status null, so that it is initialized
// here and will fail only after second click, so if invalid
// token was used we have to press the button twice before
// current status will be fetched and token will be reset.
//
// Reliable way would be to return authentication error.
// Or status update when moderator connects.
// Or we have to stop recording session when current
// moderator leaves the room.
// Failed to change, reset the token because it might
// have been wrong
my.setRecordingToken(null);
}
// Update with returned status
Toolbar.setRecordingButtonState(state);
}
);
};
return my;
}(Recording || {}));
...@@ -79,7 +79,14 @@ PeerStats.prototype.setSsrcResolution = function (ssrc, resolution) ...@@ -79,7 +79,14 @@ PeerStats.prototype.setSsrcResolution = function (ssrc, resolution)
*/ */
PeerStats.prototype.setSsrcBitrate = function (ssrc, bitrate) PeerStats.prototype.setSsrcBitrate = function (ssrc, bitrate)
{ {
this.ssrc2bitrate[ssrc] = bitrate; if(this.ssrc2bitrate[ssrc])
{
this.ssrc2bitrate[ssrc].download += bitrate.download;
this.ssrc2bitrate[ssrc].upload += bitrate.upload;
}
else {
this.ssrc2bitrate[ssrc] = bitrate;
}
}; };
/** /**
...@@ -102,6 +109,7 @@ PeerStats.prototype.setSsrcAudioLevel = function (ssrc, audioLevel) ...@@ -102,6 +109,7 @@ PeerStats.prototype.setSsrcAudioLevel = function (ssrc, audioLevel)
*/ */
PeerStats.transport = []; PeerStats.transport = [];
/** /**
* <tt>StatsCollector</tt> registers for stats updates of given * <tt>StatsCollector</tt> registers for stats updates of given
* <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular * <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular
...@@ -174,7 +182,15 @@ StatsCollector.prototype.start = function () ...@@ -174,7 +182,15 @@ StatsCollector.prototype.start = function ()
self.peerconnection.getStats( self.peerconnection.getStats(
function (report) function (report)
{ {
var results = report.result(); var results = null;
if(!report || !report.result || typeof report.result != 'function')
{
results = report;
}
else
{
results = report.result();
}
//console.error("Got interval report", results); //console.error("Got interval report", results);
self.currentAudioLevelsReport = results; self.currentAudioLevelsReport = results;
self.processAudioLevelReport(); self.processAudioLevelReport();
...@@ -193,10 +209,28 @@ StatsCollector.prototype.start = function () ...@@ -193,10 +209,28 @@ StatsCollector.prototype.start = function ()
self.peerconnection.getStats( self.peerconnection.getStats(
function (report) function (report)
{ {
var results = report.result(); var results = null;
if(!report || !report.result || typeof report.result != 'function')
{
//firefox
results = report;
}
else
{
//chrome
results = report.result();
}
//console.error("Got interval report", results); //console.error("Got interval report", results);
self.currentStatsReport = results; self.currentStatsReport = results;
self.processStatsReport(); try
{
self.processStatsReport();
}
catch(e)
{
console.error("Unsupported key:" + e);
}
self.baselineStatsReport = self.currentStatsReport; self.baselineStatsReport = self.currentStatsReport;
}, },
self.errorCallback self.errorCallback
...@@ -206,6 +240,36 @@ StatsCollector.prototype.start = function () ...@@ -206,6 +240,36 @@ StatsCollector.prototype.start = function ()
); );
}; };
var keyMap = {
"firefox": {
"ssrc": "ssrc",
"packetsReceived": "packetsReceived",
"packetsLost": "packetsLost",
"packetsSent": "packetsSent",
"bytesReceived": "bytesReceived",
"bytesSent": "bytesSent"
},
"chrome": {
"receiveBandwidth": "googAvailableReceiveBandwidth",
"sendBandwidth": "googAvailableSendBandwidth",
"remoteAddress": "googRemoteAddress",
"transportType": "googTransportType",
"localAddress": "googLocalAddress",
"activeConnection": "googActiveConnection",
"ssrc": "ssrc",
"packetsReceived": "packetsReceived",
"packetsSent": "packetsSent",
"packetsLost": "packetsLost",
"bytesReceived": "bytesReceived",
"bytesSent": "bytesSent",
"googFrameHeightReceived": "googFrameHeightReceived",
"googFrameWidthReceived": "googFrameWidthReceived",
"googFrameHeightSent": "googFrameHeightSent",
"googFrameWidthSent": "googFrameWidthSent",
"audioInputLevel": "audioInputLevel",
"audioOutputLevel": "audioOutputLevel"
}
};
/** /**
* Stats processing logic. * Stats processing logic.
...@@ -217,23 +281,29 @@ StatsCollector.prototype.processStatsReport = function () { ...@@ -217,23 +281,29 @@ StatsCollector.prototype.processStatsReport = function () {
for (var idx in this.currentStatsReport) { for (var idx in this.currentStatsReport) {
var now = this.currentStatsReport[idx]; var now = this.currentStatsReport[idx];
if (now.stat('googAvailableReceiveBandwidth') || try {
now.stat('googAvailableSendBandwidth')) if (getStatValue(now, 'receiveBandwidth') ||
{ getStatValue(now, 'sendBandwidth')) {
PeerStats.bandwidth = { PeerStats.bandwidth = {
"download": Math.round( "download": Math.round(
(now.stat('googAvailableReceiveBandwidth')) / 1000), (getStatValue(now, 'receiveBandwidth')) / 1000),
"upload": Math.round( "upload": Math.round(
(now.stat('googAvailableSendBandwidth')) / 1000) (getStatValue(now, 'sendBandwidth')) / 1000)
}; };
}
} }
catch(e){/*not supported*/}
if(now.type == 'googCandidatePair') if(now.type == 'googCandidatePair')
{ {
var ip = now.stat('googRemoteAddress'); var ip, type, localIP, active;
var type = now.stat("googTransportType"); try {
var localIP = now.stat("googLocalAddress"); ip = getStatValue(now, 'remoteAddress');
var active = now.stat("googActiveConnection"); type = getStatValue(now, "transportType");
localIP = getStatValue(now, "localAddress");
active = getStatValue(now, "activeConnection");
}
catch(e){/*not supported*/}
if(!ip || !type || !localIP || active != "true") if(!ip || !type || !localIP || active != "true")
continue; continue;
var addressSaved = false; var addressSaved = false;
...@@ -252,17 +322,32 @@ StatsCollector.prototype.processStatsReport = function () { ...@@ -252,17 +322,32 @@ StatsCollector.prototype.processStatsReport = function () {
continue; continue;
} }
if (now.type != 'ssrc') { if(now.type == "candidatepair")
{
if(now.state == "succeeded")
continue;
var local = this.currentStatsReport[now.localCandidateId];
var remote = this.currentStatsReport[now.remoteCandidateId];
PeerStats.transport.push({localip: local.ipAddress + ":" + local.portNumber,
ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport});
}
if (now.type != 'ssrc' && now.type != "outboundrtp" &&
now.type != "inboundrtp") {
continue; continue;
} }
var before = this.baselineStatsReport[idx]; var before = this.baselineStatsReport[idx];
if (!before) { if (!before) {
console.warn(now.stat('ssrc') + ' not enough data'); console.warn(getStatValue(now, 'ssrc') + ' not enough data');
continue; continue;
} }
var ssrc = now.stat('ssrc'); var ssrc = getStatValue(now, 'ssrc');
if(!ssrc)
continue;
var jid = ssrc2jid[ssrc]; var jid = ssrc2jid[ssrc];
if (!jid) { if (!jid) {
console.warn("No jid for ssrc: " + ssrc); console.warn("No jid for ssrc: " + ssrc);
...@@ -278,31 +363,30 @@ StatsCollector.prototype.processStatsReport = function () { ...@@ -278,31 +363,30 @@ StatsCollector.prototype.processStatsReport = function () {
var isDownloadStream = true; var isDownloadStream = true;
var key = 'packetsReceived'; var key = 'packetsReceived';
if (!now.stat(key)) if (!getStatValue(now, key))
{ {
isDownloadStream = false; isDownloadStream = false;
key = 'packetsSent'; key = 'packetsSent';
if (!now.stat(key)) if (!getStatValue(now, key))
{ {
console.error("No packetsReceived nor packetSent stat found"); console.warn("No packetsReceived nor packetSent stat found");
this.stop(); continue;
return;
} }
} }
var packetsNow = now.stat(key); var packetsNow = getStatValue(now, key);
if(!packetsNow || packetsNow < 0) if(!packetsNow || packetsNow < 0)
packetsNow = 0; packetsNow = 0;
var packetsBefore = before.stat(key); var packetsBefore = getStatValue(before, key);
if(!packetsBefore || packetsBefore < 0) if(!packetsBefore || packetsBefore < 0)
packetsBefore = 0; packetsBefore = 0;
var packetRate = packetsNow - packetsBefore; var packetRate = packetsNow - packetsBefore;
if(!packetRate || packetRate < 0) if(!packetRate || packetRate < 0)
packetRate = 0; packetRate = 0;
var currentLoss = now.stat('packetsLost'); var currentLoss = getStatValue(now, 'packetsLost');
if(!currentLoss || currentLoss < 0) if(!currentLoss || currentLoss < 0)
currentLoss = 0; currentLoss = 0;
var previousLoss = before.stat('packetsLost'); var previousLoss = getStatValue(before, 'packetsLost');
if(!previousLoss || previousLoss < 0) if(!previousLoss || previousLoss < 0)
previousLoss = 0; previousLoss = 0;
var lossRate = currentLoss - previousLoss; var lossRate = currentLoss - previousLoss;
...@@ -315,16 +399,18 @@ StatsCollector.prototype.processStatsReport = function () { ...@@ -315,16 +399,18 @@ StatsCollector.prototype.processStatsReport = function () {
"packetsLost": lossRate, "packetsLost": lossRate,
"isDownloadStream": isDownloadStream}); "isDownloadStream": isDownloadStream});
var bytesReceived = 0, bytesSent = 0; var bytesReceived = 0, bytesSent = 0;
if(now.stat("bytesReceived")) if(getStatValue(now, "bytesReceived"))
{ {
bytesReceived = now.stat("bytesReceived") - bytesReceived = getStatValue(now, "bytesReceived") -
before.stat("bytesReceived"); getStatValue(before, "bytesReceived");
} }
if(now.stat("bytesSent")) if(getStatValue(now, "bytesSent"))
{ {
bytesSent = now.stat("bytesSent") - before.stat("bytesSent"); bytesSent = getStatValue(now, "bytesSent") -
getStatValue(before, "bytesSent");
} }
var time = Math.round((now.timestamp - before.timestamp) / 1000); var time = Math.round((now.timestamp - before.timestamp) / 1000);
...@@ -349,19 +435,21 @@ StatsCollector.prototype.processStatsReport = function () { ...@@ -349,19 +435,21 @@ StatsCollector.prototype.processStatsReport = function () {
jidStats.setSsrcBitrate(ssrc, { jidStats.setSsrcBitrate(ssrc, {
"download": bytesReceived, "download": bytesReceived,
"upload": bytesSent}); "upload": bytesSent});
var resolution = {height: null, width: null}; var resolution = {height: null, width: null};
if(now.stat("googFrameHeightReceived") && try {
now.stat("googFrameWidthReceived")) if (getStatValue(now, "googFrameHeightReceived") &&
{ getStatValue(now, "googFrameWidthReceived")) {
resolution.height = now.stat("googFrameHeightReceived"); resolution.height = getStatValue(now, "googFrameHeightReceived");
resolution.width = now.stat("googFrameWidthReceived"); resolution.width = getStatValue(now, "googFrameWidthReceived");
} }
else if(now.stat("googFrameHeightSent") && else if (getStatValue(now, "googFrameHeightSent") &&
now.stat("googFrameWidthSent")) getStatValue(now, "googFrameWidthSent")) {
{ resolution.height = getStatValue(now, "googFrameHeightSent");
resolution.height = now.stat("googFrameHeightSent"); resolution.width = getStatValue(now, "googFrameWidthSent");
resolution.width = now.stat("googFrameWidthSent"); }
} }
catch(e){/*not supported*/}
if(resolution.height && resolution.width) if(resolution.height && resolution.width)
{ {
...@@ -403,6 +491,8 @@ StatsCollector.prototype.processStatsReport = function () { ...@@ -403,6 +491,8 @@ StatsCollector.prototype.processStatsReport = function () {
self.jid2stats[jid].ssrc2bitrate[ssrc].download; self.jid2stats[jid].ssrc2bitrate[ssrc].download;
bitrateUpload += bitrateUpload +=
self.jid2stats[jid].ssrc2bitrate[ssrc].upload; self.jid2stats[jid].ssrc2bitrate[ssrc].upload;
delete self.jid2stats[jid].ssrc2bitrate[ssrc];
} }
); );
resolutions[jid] = self.jid2stats[jid].ssrc2resolution; resolutions[jid] = self.jid2stats[jid].ssrc2resolution;
...@@ -454,11 +544,11 @@ StatsCollector.prototype.processAudioLevelReport = function () ...@@ -454,11 +544,11 @@ StatsCollector.prototype.processAudioLevelReport = function ()
var before = this.baselineAudioLevelsReport[idx]; var before = this.baselineAudioLevelsReport[idx];
if (!before) if (!before)
{ {
console.warn(now.stat('ssrc') + ' not enough data'); console.warn(getStatValue(now, 'ssrc') + ' not enough data');
continue; continue;
} }
var ssrc = now.stat('ssrc'); var ssrc = getStatValue(now, 'ssrc');
var jid = ssrc2jid[ssrc]; var jid = ssrc2jid[ssrc];
if (!jid) if (!jid)
{ {
...@@ -474,9 +564,19 @@ StatsCollector.prototype.processAudioLevelReport = function () ...@@ -474,9 +564,19 @@ StatsCollector.prototype.processAudioLevelReport = function ()
} }
// Audio level // Audio level
var audioLevel = now.stat('audioInputLevel'); var audioLevel = null;
if (!audioLevel)
audioLevel = now.stat('audioOutputLevel'); try {
audioLevel = getStatValue(now, 'audioInputLevel');
if (!audioLevel)
audioLevel = getStatValue(now, 'audioOutputLevel');
}
catch(e) {/*not supported*/
console.warn("Audio Levels are not available in the statistics.");
clearInterval(this.audioLevelsIntervalId);
return;
}
if (audioLevel) if (audioLevel)
{ {
// TODO: can't find specs about what this value really is, // TODO: can't find specs about what this value really is,
...@@ -491,3 +591,10 @@ StatsCollector.prototype.processAudioLevelReport = function () ...@@ -491,3 +591,10 @@ StatsCollector.prototype.processAudioLevelReport = function ()
}; };
function getStatValue(item, name) {
if(!keyMap[RTC.browser][name])
throw "The property isn't supported!";
var key = keyMap[RTC.browser][name];
return RTC.browser == "chrome"? item.stat(key) : item[key];
}
\ No newline at end of file
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Forbidden</title>
</head>
<body>
<h1>Forbidden</h1>
<h4>This is a private folder</h4>
</body>
</html>
\ No newline at end of file
#OfMeet Settings
server=btg199251
port=7443
protocol=https://
...@@ -51,12 +51,10 @@ var Util = (function (my) { ...@@ -51,12 +51,10 @@ var Util = (function (my) {
* Returns the available video width. * Returns the available video width.
*/ */
my.getAvailableVideoWidth = function () { my.getAvailableVideoWidth = function () {
var chatspaceWidth var rightPanelWidth
= (Chat.isVisible() || ContactList.isVisible()) = PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
? $('#chatspace').width()
: 0;
return window.innerWidth - chatspaceWidth; return window.innerWidth - rightPanelWidth;
}; };
my.imageToGrayScale = function (canvas) { my.imageToGrayScale = function (canvas) {
......
...@@ -9,11 +9,24 @@ var VideoLayout = (function (my) { ...@@ -9,11 +9,24 @@ var VideoLayout = (function (my) {
updateInProgress: false, updateInProgress: false,
newSrc: '' newSrc: ''
}; };
var defaultLocalDisplayName = "Me";
my.connectionIndicators = {}; my.connectionIndicators = {};
my.changeLocalAudio = function(stream) { my.isInLastN = function(resource) {
return lastNCount < 0 // lastN is disabled, return true
|| (lastNCount > 0 && lastNEndpointsCache.length == 0) // lastNEndpoints cache not built yet, return true
|| (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
};
my.changeLocalStream = function (stream) {
connection.jingle.localAudio = stream; connection.jingle.localAudio = stream;
VideoLayout.changeLocalVideo(stream, true);
}
my.changeLocalAudio = function(stream) {
connection.jingle.localAudio = stream;
RTC.attachMediaStream($('#localAudio'), stream); RTC.attachMediaStream($('#localAudio'), stream);
document.getElementById('localAudio').autoplay = true; document.getElementById('localAudio').autoplay = true;
document.getElementById('localAudio').volume = 0; document.getElementById('localAudio').volume = 0;
...@@ -23,7 +36,7 @@ var VideoLayout = (function (my) { ...@@ -23,7 +36,7 @@ var VideoLayout = (function (my) {
connection.jingle.localVideo = stream; connection.jingle.localVideo = stream;
var localVideo = document.createElement('video'); var localVideo = document.createElement('video');
localVideo.id = 'localVideo_' + stream.id; localVideo.id = 'localVideo_' + RTC.getStreamID(stream);
localVideo.autoplay = true; localVideo.autoplay = true;
localVideo.volume = 0; // is it required if audio is separated ? localVideo.volume = 0; // is it required if audio is separated ?
localVideo.oncontextmenu = function () { return false; }; localVideo.oncontextmenu = function () { return false; };
...@@ -45,10 +58,10 @@ var VideoLayout = (function (my) { ...@@ -45,10 +58,10 @@ var VideoLayout = (function (my) {
// Add click handler to both video and video wrapper elements in case // Add click handler to both video and video wrapper elements in case
// there's no video. // there's no video.
localVideoSelector.click(function () { localVideoSelector.click(function () {
VideoLayout.handleVideoThumbClicked(localVideo.src); VideoLayout.handleVideoThumbClicked(RTC.getVideoSrc(localVideo), false, connection.emuc.myroomjid);
}); });
$('#localVideoContainer').click(function () { $('#localVideoContainer').click(function () {
VideoLayout.handleVideoThumbClicked(localVideo.src); VideoLayout.handleVideoThumbClicked(RTC.getVideoSrc(localVideo), false, connection.emuc.myroomjid);
}); });
// Add hover handler // Add hover handler
...@@ -58,14 +71,14 @@ var VideoLayout = (function (my) { ...@@ -58,14 +71,14 @@ var VideoLayout = (function (my) {
}, },
function() { function() {
if (!VideoLayout.isLargeVideoVisible() if (!VideoLayout.isLargeVideoVisible()
|| localVideo.src !== $('#largeVideo').attr('src')) || RTC.getVideoSrc(localVideo) !== RTC.getVideoSrc($('#largeVideo')[0]))
VideoLayout.showDisplayName('localVideoContainer', false); VideoLayout.showDisplayName('localVideoContainer', false);
} }
); );
// Add stream ended handler // Add stream ended handler
stream.onended = function () { stream.onended = function () {
localVideoContainer.removeChild(localVideo); localVideoContainer.removeChild(localVideo);
VideoLayout.updateRemovedVideo(localVideo.src); VideoLayout.updateRemovedVideo(RTC.getVideoSrc(localVideo));
}; };
// Flip video x axis if needed // Flip video x axis if needed
flipXLocalVideo = flipX; flipXLocalVideo = flipX;
...@@ -76,9 +89,16 @@ var VideoLayout = (function (my) { ...@@ -76,9 +89,16 @@ var VideoLayout = (function (my) {
var videoStream = simulcast.getLocalVideoStream(); var videoStream = simulcast.getLocalVideoStream();
RTC.attachMediaStream(localVideoSelector, videoStream); RTC.attachMediaStream(localVideoSelector, videoStream);
localVideoSrc = localVideo.src; localVideoSrc = RTC.getVideoSrc(localVideo);
var myResourceJid = null;
if(connection.emuc.myroomjid)
{
myResourceJid = Strophe.getResourceFromJid(connection.emuc.myroomjid);
}
VideoLayout.updateLargeVideo(localVideoSrc, 0,
myResourceJid);
VideoLayout.updateLargeVideo(localVideoSrc, 0);
}; };
/** /**
...@@ -87,7 +107,7 @@ var VideoLayout = (function (my) { ...@@ -87,7 +107,7 @@ var VideoLayout = (function (my) {
* @param removedVideoSrc src stream identifier of the video. * @param removedVideoSrc src stream identifier of the video.
*/ */
my.updateRemovedVideo = function(removedVideoSrc) { my.updateRemovedVideo = function(removedVideoSrc) {
if (removedVideoSrc === $('#largeVideo').attr('src')) { if (removedVideoSrc === RTC.getVideoSrc($('#largeVideo')[0])) {
// this is currently displayed as large // this is currently displayed as large
// pick the last visible video in the row // pick the last visible video in the row
// if nobody else is left, this picks the local video // if nobody else is left, this picks the local video
...@@ -99,7 +119,7 @@ var VideoLayout = (function (my) { ...@@ -99,7 +119,7 @@ var VideoLayout = (function (my) {
console.info("Last visible video no longer exists"); console.info("Last visible video no longer exists");
pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0); pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
if (!pick || !pick.src) { if (!pick || !RTC.getVideoSrc(pick)) {
// Try local video // Try local video
console.info("Fallback to local video..."); console.info("Fallback to local video...");
pick = $('#remoteVideos>span>span>video').get(0); pick = $('#remoteVideos>span>span>video').get(0);
...@@ -108,21 +128,40 @@ var VideoLayout = (function (my) { ...@@ -108,21 +128,40 @@ var VideoLayout = (function (my) {
// mute if localvideo // mute if localvideo
if (pick) { if (pick) {
VideoLayout.updateLargeVideo(pick.src, pick.volume); var container = pick.parentNode;
var jid = null;
if(container)
{
if(container.id == "localVideoWrapper")
{
jid = Strophe.getResourceFromJid(connection.emuc.myroomjid);
}
else
{
jid = VideoLayout.getPeerContainerResourceJid(container);
}
}
VideoLayout.updateLargeVideo(RTC.getVideoSrc(pick), pick.volume, jid);
} else { } else {
console.warn("Failed to elect large video"); console.warn("Failed to elect large video");
} }
} }
}; };
my.getLargeVideoState = function () {
return largeVideoState;
}
/** /**
* Updates the large video with the given new video source. * Updates the large video with the given new video source.
*/ */
my.updateLargeVideo = function(newSrc, vol) { my.updateLargeVideo = function(newSrc, vol, jid) {
console.log('hover in', newSrc); console.log('hover in', newSrc);
if ($('#largeVideo').attr('src') != newSrc) { if (RTC.getVideoSrc($('#largeVideo')[0]) != newSrc) {
$('#activeSpeakerAvatar').css('visibility', 'hidden');
// Due to the simulcast the localVideoSrc may have changed when the // Due to the simulcast the localVideoSrc may have changed when the
// fadeOut event triggers. In that case the getJidFromVideoSrc and // fadeOut event triggers. In that case the getJidFromVideoSrc and
// isVideoSrcDesktop methods will not function correctly. // isVideoSrcDesktop methods will not function correctly.
...@@ -133,15 +172,22 @@ var VideoLayout = (function (my) { ...@@ -133,15 +172,22 @@ var VideoLayout = (function (my) {
largeVideoState.newSrc = newSrc; largeVideoState.newSrc = newSrc;
largeVideoState.isVisible = $('#largeVideo').is(':visible'); largeVideoState.isVisible = $('#largeVideo').is(':visible');
largeVideoState.isDesktop = isVideoSrcDesktop(newSrc); largeVideoState.isDesktop = isVideoSrcDesktop(jid);
largeVideoState.userJid = getJidFromVideoSrc(newSrc); if(jid2Ssrc[largeVideoState.userJid] ||
(connection && connection.emuc.myroomjid &&
largeVideoState.userJid == Strophe.getResourceFromJid(connection.emuc.myroomjid)))
{
largeVideoState.oldJid = largeVideoState.userJid;
}
else
{
largeVideoState.oldJid = null;
}
largeVideoState.userJid = jid;
// Screen stream is already rotated // Screen stream is already rotated
largeVideoState.flipX = (newSrc === localVideoSrc) && flipXLocalVideo; largeVideoState.flipX = (newSrc === localVideoSrc) && flipXLocalVideo;
var oldSrc = $('#largeVideo').attr('src');
largeVideoState.oldJid = getJidFromVideoSrc(oldSrc);
var userChanged = false; var userChanged = false;
if (largeVideoState.oldJid != largeVideoState.userJid) { if (largeVideoState.oldJid != largeVideoState.userJid) {
userChanged = true; userChanged = true;
...@@ -155,9 +201,12 @@ var VideoLayout = (function (my) { ...@@ -155,9 +201,12 @@ var VideoLayout = (function (my) {
var doUpdate = function () { var doUpdate = function () {
Avatar.updateActiveSpeakerAvatarSrc(largeVideoState.userJid);
if (!userChanged && largeVideoState.preload if (!userChanged && largeVideoState.preload
&& largeVideoState.preload != null && largeVideoState.preload != null
&& $(largeVideoState.preload).attr('src') == newSrc) { && RTC.getVideoSrc($(largeVideoState.preload)[0]) == newSrc)
{
console.info('Switching to preloaded video'); console.info('Switching to preloaded video');
var attributes = $('#largeVideo').prop("attributes"); var attributes = $('#largeVideo').prop("attributes");
...@@ -183,7 +232,7 @@ var VideoLayout = (function (my) { ...@@ -183,7 +232,7 @@ var VideoLayout = (function (my) {
largeVideoState.preload = null; largeVideoState.preload = null;
largeVideoState.preload_ssrc = 0; largeVideoState.preload_ssrc = 0;
} else { } else {
$('#largeVideo').attr('src', largeVideoState.newSrc); RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
} }
var videoTransform = document.getElementById('largeVideo') var videoTransform = document.getElementById('largeVideo')
...@@ -211,14 +260,12 @@ var VideoLayout = (function (my) { ...@@ -211,14 +260,12 @@ var VideoLayout = (function (my) {
// Only if the large video is currently visible. // Only if the large video is currently visible.
// Disable previous dominant speaker video. // Disable previous dominant speaker video.
if (largeVideoState.oldJid) { if (largeVideoState.oldJid) {
var oldResourceJid = Strophe.getResourceFromJid(largeVideoState.oldJid); VideoLayout.enableDominantSpeaker(largeVideoState.oldJid, false);
VideoLayout.enableDominantSpeaker(oldResourceJid, false);
} }
// Enable new dominant speaker in the remote videos section. // Enable new dominant speaker in the remote videos section.
if (largeVideoState.userJid) { if (largeVideoState.userJid) {
var resourceJid = Strophe.getResourceFromJid(largeVideoState.userJid); VideoLayout.enableDominantSpeaker(largeVideoState.userJid, true);
VideoLayout.enableDominantSpeaker(resourceJid, true);
} }
if (userChanged && largeVideoState.isVisible) { if (userChanged && largeVideoState.isVisible) {
...@@ -227,6 +274,10 @@ var VideoLayout = (function (my) { ...@@ -227,6 +274,10 @@ var VideoLayout = (function (my) {
$(this).fadeIn(300); $(this).fadeIn(300);
} }
if(userChanged) {
Avatar.showUserAvatar(largeVideoState.oldJid);
}
largeVideoState.updateInProgress = false; largeVideoState.updateInProgress = false;
}; };
...@@ -239,17 +290,20 @@ var VideoLayout = (function (my) { ...@@ -239,17 +290,20 @@ var VideoLayout = (function (my) {
} }
}; };
my.handleVideoThumbClicked = function(videoSrc, noPinnedEndpointChangedEvent) { my.handleVideoThumbClicked = function(videoSrc, noPinnedEndpointChangedEvent, jid) {
// Restore style for previously focused video // Restore style for previously focused video
var focusJid = getJidFromVideoSrc(focusedVideoSrc); var oldContainer = null;
var oldContainer = getParticipantContainer(focusJid); if(focusedVideoSrc) {
var focusJid = focusedVideoSrc.jid;
oldContainer = getParticipantContainer(focusJid);
}
if (oldContainer) { if (oldContainer) {
oldContainer.removeClass("videoContainerFocused"); oldContainer.removeClass("videoContainerFocused");
} }
// Unlock current focused. // Unlock current focused.
if (focusedVideoSrc === videoSrc) if (focusedVideoSrc && focusedVideoSrc.src === videoSrc)
{ {
focusedVideoSrc = null; focusedVideoSrc = null;
var dominantSpeakerVideo = null; var dominantSpeakerVideo = null;
...@@ -260,7 +314,7 @@ var VideoLayout = (function (my) { ...@@ -260,7 +314,7 @@ var VideoLayout = (function (my) {
.get(0); .get(0);
if (dominantSpeakerVideo) { if (dominantSpeakerVideo) {
VideoLayout.updateLargeVideo(dominantSpeakerVideo.src, 1); VideoLayout.updateLargeVideo(RTC.getVideoSrc(dominantSpeakerVideo), 1, currentDominantSpeaker);
} }
} }
...@@ -271,17 +325,19 @@ var VideoLayout = (function (my) { ...@@ -271,17 +325,19 @@ var VideoLayout = (function (my) {
} }
// Lock new video // Lock new video
focusedVideoSrc = videoSrc; focusedVideoSrc = {
src: videoSrc,
jid: jid
};
// Update focused/pinned interface. // Update focused/pinned interface.
var userJid = getJidFromVideoSrc(videoSrc); if (jid)
if (userJid)
{ {
var container = getParticipantContainer(userJid); var container = getParticipantContainer(jid);
container.addClass("videoContainerFocused"); container.addClass("videoContainerFocused");
if (!noPinnedEndpointChangedEvent) { if (!noPinnedEndpointChangedEvent) {
$(document).trigger("pinnedendpointchanged", [userJid]); $(document).trigger("pinnedendpointchanged", [jid]);
} }
} }
...@@ -293,7 +349,7 @@ var VideoLayout = (function (my) { ...@@ -293,7 +349,7 @@ var VideoLayout = (function (my) {
// this isn't a prezi. // this isn't a prezi.
$(document).trigger("video.selected", [false]); $(document).trigger("video.selected", [false]);
VideoLayout.updateLargeVideo(videoSrc, 1); VideoLayout.updateLargeVideo(videoSrc, 1, Strophe.getResourceFromJid(jid));
$('audio').each(function (idx, el) { $('audio').each(function (idx, el) {
if (el.id.indexOf('mixedmslabel') !== -1) { if (el.id.indexOf('mixedmslabel') !== -1) {
...@@ -339,8 +395,7 @@ var VideoLayout = (function (my) { ...@@ -339,8 +395,7 @@ var VideoLayout = (function (my) {
* Shows/hides the large video. * Shows/hides the large video.
*/ */
my.setLargeVideoVisible = function(isVisible) { my.setLargeVideoVisible = function(isVisible) {
var largeVideoJid = getJidFromVideoSrc($('#largeVideo').attr('src')); var resourceJid = largeVideoState.userJid;
var resourceJid = Strophe.getResourceFromJid(largeVideoJid);
if (isVisible) { if (isVisible) {
$('#largeVideo').css({visibility: 'visible'}); $('#largeVideo').css({visibility: 'visible'});
...@@ -368,12 +423,13 @@ var VideoLayout = (function (my) { ...@@ -368,12 +423,13 @@ var VideoLayout = (function (my) {
* in the document and creates it eventually. * in the document and creates it eventually.
* *
* @param peerJid peer Jid to check. * @param peerJid peer Jid to check.
* @param userId user email or id for setting the avatar
* *
* @return Returns <tt>true</tt> if the peer container exists, * @return Returns <tt>true</tt> if the peer container exists,
* <tt>false</tt> - otherwise * <tt>false</tt> - otherwise
*/ */
my.ensurePeerContainerExists = function(peerJid) { my.ensurePeerContainerExists = function(peerJid, userId) {
ContactList.ensureAddContact(peerJid); ContactList.ensureAddContact(peerJid, userId);
var resourceJid = Strophe.getResourceFromJid(peerJid); var resourceJid = Strophe.getResourceFromJid(peerJid);
...@@ -382,14 +438,15 @@ var VideoLayout = (function (my) { ...@@ -382,14 +438,15 @@ var VideoLayout = (function (my) {
if ($('#' + videoSpanId).length > 0) { if ($('#' + videoSpanId).length > 0) {
// If there's been a focus change, make sure we add focus related // If there's been a focus change, make sure we add focus related
// interface!! // interface!!
if (focus && $('#remote_popupmenu_' + resourceJid).length <= 0) if (focus && $('#remote_popupmenu_' + resourceJid).length <= 0) {
addRemoteVideoMenu( peerJid, addRemoteVideoMenu(peerJid,
document.getElementById(videoSpanId)); document.getElementById(videoSpanId));
}
} }
else { else {
var container var container =
= VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId); VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId, userId);
Avatar.setUserAvatar(peerJid, userId);
// Set default display name. // Set default display name.
setDisplayName(videoSpanId); setDisplayName(videoSpanId);
...@@ -438,7 +495,7 @@ var VideoLayout = (function (my) { ...@@ -438,7 +495,7 @@ var VideoLayout = (function (my) {
? document.createElement('video') ? document.createElement('video')
: document.createElement('audio'); : document.createElement('audio');
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
+ sid + '_' + stream.id; + sid + '_' + RTC.getStreamID(stream);
element.id = id; element.id = id;
element.autoplay = true; element.autoplay = true;
...@@ -469,7 +526,7 @@ var VideoLayout = (function (my) { ...@@ -469,7 +526,7 @@ var VideoLayout = (function (my) {
RTC.attachMediaStream(sel, videoStream); RTC.attachMediaStream(sel, videoStream);
if (isVideo) if (isVideo)
waitForRemoteVideo(sel, thessrc, stream); waitForRemoteVideo(sel, thessrc, stream, peerJid);
} }
stream.onended = function () { stream.onended = function () {
...@@ -491,7 +548,7 @@ var VideoLayout = (function (my) { ...@@ -491,7 +548,7 @@ var VideoLayout = (function (my) {
var videoThumb = $('#' + container.id + '>video').get(0); var videoThumb = $('#' + container.id + '>video').get(0);
if (videoThumb) if (videoThumb)
VideoLayout.handleVideoThumbClicked(videoThumb.src); VideoLayout.handleVideoThumbClicked(RTC.getVideoSrc(videoThumb), false, peerJid);
event.preventDefault(); event.preventDefault();
return false; return false;
...@@ -506,13 +563,13 @@ var VideoLayout = (function (my) { ...@@ -506,13 +563,13 @@ var VideoLayout = (function (my) {
var videoSrc = null; var videoSrc = null;
if ($('#' + container.id + '>video') if ($('#' + container.id + '>video')
&& $('#' + container.id + '>video').length > 0) { && $('#' + container.id + '>video').length > 0) {
videoSrc = $('#' + container.id + '>video').get(0).src; videoSrc = RTC.getVideoSrc($('#' + container.id + '>video').get(0));
} }
// If the video has been "pinned" by the user we want to // If the video has been "pinned" by the user we want to
// keep the display name on place. // keep the display name on place.
if (!VideoLayout.isLargeVideoVisible() if (!VideoLayout.isLargeVideoVisible()
|| videoSrc !== $('#largeVideo').attr('src')) || videoSrc !== RTC.getVideoSrc($('#largeVideo')[0]))
VideoLayout.showDisplayName(container.id, false); VideoLayout.showDisplayName(container.id, false);
} }
); );
...@@ -537,13 +594,11 @@ var VideoLayout = (function (my) { ...@@ -537,13 +594,11 @@ var VideoLayout = (function (my) {
var removedVideoSrc = null; var removedVideoSrc = null;
if (isVideo) { if (isVideo) {
select = $('#' + container.id + '>video'); select = $('#' + container.id + '>video');
removedVideoSrc = select.get(0).src; removedVideoSrc = RTC.getVideoSrc(select.get(0));
} }
else else
select = $('#' + container.id + '>audio'); select = $('#' + container.id + '>audio');
// Remove video source from the mapping.
delete videoSrcToSsrc[removedVideoSrc];
// Mark video as removed to cancel waiting loop(if video is removed // Mark video as removed to cancel waiting loop(if video is removed
// before has started) // before has started)
...@@ -586,14 +641,17 @@ var VideoLayout = (function (my) { ...@@ -586,14 +641,17 @@ var VideoLayout = (function (my) {
peerContainer.show(); peerContainer.show();
} }
// TODO(gp) add proper avatars handling.
if (state == 'show') if (state == 'show')
{ {
peerContainer.css('-webkit-filter', ''); // peerContainer.css('-webkit-filter', '');
var jid = connection.emuc.findJidFromResource(resourceJid);
Avatar.showUserAvatar(jid, false);
} }
else // if (state == 'avatar') else // if (state == 'avatar')
{ {
peerContainer.css('-webkit-filter', 'grayscale(100%)'); // peerContainer.css('-webkit-filter', 'grayscale(100%)');
var jid = connection.emuc.findJidFromResource(resourceJid);
Avatar.showUserAvatar(jid, true);
} }
} }
else if (peerContainer.is(':visible') && isHide) else if (peerContainer.is(':visible') && isHide)
...@@ -619,7 +677,7 @@ var VideoLayout = (function (my) { ...@@ -619,7 +677,7 @@ var VideoLayout = (function (my) {
*/ */
function setDisplayName(videoSpanId, displayName) { function setDisplayName(videoSpanId, displayName) {
var nameSpan = $('#' + videoSpanId + '>span.displayname'); var nameSpan = $('#' + videoSpanId + '>span.displayname');
var defaultLocalDisplayName = "Me"; var defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME;
// If we already have a display name for this video. // If we already have a display name for this video.
if (nameSpan.length > 0) { if (nameSpan.length > 0) {
...@@ -680,6 +738,7 @@ var VideoLayout = (function (my) { ...@@ -680,6 +738,7 @@ var VideoLayout = (function (my) {
.bind("click", function (e) { .bind("click", function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
$('#localDisplayName').hide(); $('#localDisplayName').hide();
$('#editDisplayName').show(); $('#editDisplayName').show();
$('#editDisplayName').focus(); $('#editDisplayName').focus();
...@@ -698,7 +757,7 @@ var VideoLayout = (function (my) { ...@@ -698,7 +757,7 @@ var VideoLayout = (function (my) {
}); });
} }
} }
}; }
my.inputDisplayNameHandler = function (name) { my.inputDisplayNameHandler = function (name) {
if (nickname !== name) { if (nickname !== name) {
...@@ -715,7 +774,7 @@ var VideoLayout = (function (my) { ...@@ -715,7 +774,7 @@ var VideoLayout = (function (my) {
$('#localDisplayName').text(nickname + " (me)"); $('#localDisplayName').text(nickname + " (me)");
else else
$('#localDisplayName') $('#localDisplayName')
.text(defaultLocalDisplayName); .text(interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
$('#localDisplayName').show(); $('#localDisplayName').show();
} }
...@@ -911,6 +970,10 @@ var VideoLayout = (function (my) { ...@@ -911,6 +970,10 @@ var VideoLayout = (function (my) {
$('#largeVideoContainer').width(availableWidth); $('#largeVideoContainer').width(availableWidth);
$('#largeVideoContainer').height(availableHeight); $('#largeVideoContainer').height(availableHeight);
$('#activeSpeakerAvatar').css('top',
(availableHeight - interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE) / 2);
VideoLayout.resizeThumbnails(); VideoLayout.resizeThumbnails();
}; };
...@@ -930,6 +993,8 @@ var VideoLayout = (function (my) { ...@@ -930,6 +993,8 @@ var VideoLayout = (function (my) {
$('#remoteVideos>span').width(width); $('#remoteVideos>span').width(width);
$('#remoteVideos>span').height(height); $('#remoteVideos>span').height(height);
$('.userAvatar').css('left', (width - height) / 2);
$(document).trigger("remotevideo.resized", [width, height]); $(document).trigger("remotevideo.resized", [width, height]);
}; };
...@@ -968,7 +1033,6 @@ var VideoLayout = (function (my) { ...@@ -968,7 +1033,6 @@ var VideoLayout = (function (my) {
videoSpan = document.getElementById(videoContainerId); videoSpan = document.getElementById(videoContainerId);
if (!videoSpan) { if (!videoSpan) {
console.error("No video element for jid", resourceJid);
return; return;
} }
...@@ -1184,22 +1248,6 @@ var VideoLayout = (function (my) { ...@@ -1184,22 +1248,6 @@ var VideoLayout = (function (my) {
return containerElement.id.substring(i + 12); return containerElement.id.substring(i + 12);
}; };
my.getLargeVideoResource = function () {
var largeVideoJid, largeVideoResource;
// Another approach could be to compare the srcs of the thumbnails and
// then call getPeerContainerResourceJid.
var largeVideoSsrc
= videoSrcToSsrc[$('#largeVideo').attr('src')];
if (largeVideoSsrc
/* variables/state checking to prevent exceptions */
&& (largeVideoJid = ssrc2jid[largeVideoSsrc])
&& (largeVideoResource = Strophe.getResourceFromJid(largeVideoJid)))
return largeVideoResource;
};
/** /**
* Adds the remote video menu element for the given <tt>jid</tt> in the * Adds the remote video menu element for the given <tt>jid</tt> in the
* given <tt>parentElement</tt>. * given <tt>parentElement</tt>.
...@@ -1302,7 +1350,7 @@ var VideoLayout = (function (my) { ...@@ -1302,7 +1350,7 @@ var VideoLayout = (function (my) {
// We have a video src, great! Let's update the large video // We have a video src, great! Let's update the large video
// now. // now.
VideoLayout.handleVideoThumbClicked(videoThumb.src); VideoLayout.handleVideoThumbClicked(videoThumb.src, false, jid);
} else { } else {
// If we don't have a video src for jid, there's absolutely // If we don't have a video src for jid, there's absolutely
...@@ -1430,7 +1478,7 @@ var VideoLayout = (function (my) { ...@@ -1430,7 +1478,7 @@ var VideoLayout = (function (my) {
// Update the large video if the video source is already available, // Update the large video if the video source is already available,
// otherwise wait for the "videoactive.jingle" event. // otherwise wait for the "videoactive.jingle" event.
if (video.length && video[0].currentTime > 0) if (video.length && video[0].currentTime > 0)
VideoLayout.updateLargeVideo(video[0].src); VideoLayout.updateLargeVideo(RTC.getVideoSrc(video[0]), resourceJid);
} }
}); });
...@@ -1509,7 +1557,7 @@ var VideoLayout = (function (my) { ...@@ -1509,7 +1557,7 @@ var VideoLayout = (function (my) {
// it is no longer being received. If resourceJid was being // it is no longer being received. If resourceJid was being
// displayed in the large video we have to switch to another // displayed in the large video we have to switch to another
// user. // user.
var largeVideoResource = VideoLayout.getLargeVideoResource(); var largeVideoResource = largeVideoState.userJid;
if (!updateLargeVideo && resourceJid === largeVideoResource) { if (!updateLargeVideo && resourceJid === largeVideoResource) {
updateLargeVideo = true; updateLargeVideo = true;
} }
...@@ -1527,36 +1575,26 @@ var VideoLayout = (function (my) { ...@@ -1527,36 +1575,26 @@ var VideoLayout = (function (my) {
if (!isVisible) { if (!isVisible) {
console.log("Add to last N", resourceJid); console.log("Add to last N", resourceJid);
mediaStreams.some(function (mediaStream) { var jid = connection.emuc.findJidFromResource(resourceJid);
if (mediaStream.peerjid var mediaStream = mediaStreams[jid][MediaStream.VIDEO_TYPE];
&& Strophe.getResourceFromJid(mediaStream.peerjid) var sel = $('#participant_' + resourceJid + '>video');
=== resourceJid
&& mediaStream.type === mediaStream.VIDEO_TYPE) {
var sel = $('#participant_' + resourceJid + '>video');
var videoStream = simulcast.getReceivingVideoStream(mediaStream.stream);
RTC.attachMediaStream(sel, videoStream);
videoSrcToSsrc[sel.attr('src')] = mediaStream.ssrc;
if (lastNPickupJid == mediaStream.peerjid) {
// Clean up the lastN pickup jid.
lastNPickupJid = null;
// Don't fire the events again, they've already
// been fired in the contact list click handler.
VideoLayout.handleVideoThumbClicked($(sel).attr('src'), false);
updateLargeVideo = false;
}
waitForRemoteVideo( var videoStream = simulcast.getReceivingVideoStream(
sel, mediaStream.stream);
mediaStream.ssrc, RTC.attachMediaStream(sel, videoStream);
mediaStream.stream); if (lastNPickupJid == mediaStream.peerjid) {
return true; // Clean up the lastN pickup jid.
} lastNPickupJid = null;
});
// Don't fire the events again, they've already
// been fired in the contact list click handler.
VideoLayout.handleVideoThumbClicked($(sel).attr('src'), false, mediaStream.peerjid);
updateLargeVideo = false;
}
waitForRemoteVideo(sel, mediaStream.ssrc, mediaStream.stream, resourceJid);
} }
}); })
} }
// The endpoint that was being shown in the large video has dropped out // The endpoint that was being shown in the large video has dropped out
...@@ -1611,7 +1649,7 @@ var VideoLayout = (function (my) { ...@@ -1611,7 +1649,7 @@ var VideoLayout = (function (my) {
|| (parentResourceJid || (parentResourceJid
&& VideoLayout.getDominantSpeakerResourceJid() && VideoLayout.getDominantSpeakerResourceJid()
=== parentResourceJid)) { === parentResourceJid)) {
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1); VideoLayout.updateLargeVideo(RTC.getVideoSrc(videoelem[0]), 1, parentResourceJid);
} }
VideoLayout.showFocusIndicator(); VideoLayout.showFocusIndicator();
...@@ -1622,7 +1660,15 @@ var VideoLayout = (function (my) { ...@@ -1622,7 +1660,15 @@ var VideoLayout = (function (my) {
endpointSimulcastLayers.forEach(function (esl) { endpointSimulcastLayers.forEach(function (esl) {
var resource = esl.endpoint; var resource = esl.endpoint;
if (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1) {
// if lastN is enabled *and* the endpoint is *not* in the lastN set,
// then ignore the event (= do not preload anything).
//
// The bridge could probably stop sending this message if it's for
// an endpoint that's not in lastN.
if (lastNCount != -1
&& (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
return; return;
} }
...@@ -1639,12 +1685,8 @@ var VideoLayout = (function (my) { ...@@ -1639,12 +1685,8 @@ var VideoLayout = (function (my) {
console.info([esl, primarySSRC, msid, session, electedStream]); console.info([esl, primarySSRC, msid, session, electedStream]);
var msidParts = msid.split(' '); var msidParts = msid.split(' ');
var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join(''));
// FIXME(gp) here we should use the VideoLayout.getPeerContainerResource var preload = (Strophe.getResourceFromJid(ssrc2jid[primarySSRC]) == largeVideoState.userJid);
// and VideoLayout.getLargeVideoResource methods.
var preload = (ssrc2jid[videoSrcToSsrc[selRemoteVideo.attr('src')]]
== ssrc2jid[videoSrcToSsrc[largeVideoState.newSrc]]);
if (preload) { if (preload) {
if (largeVideoState.preload) if (largeVideoState.preload)
...@@ -1656,9 +1698,7 @@ var VideoLayout = (function (my) { ...@@ -1656,9 +1698,7 @@ var VideoLayout = (function (my) {
// ssrcs are unique in an rtp session // ssrcs are unique in an rtp session
largeVideoState.preload_ssrc = primarySSRC; largeVideoState.preload_ssrc = primarySSRC;
var electedStreamUrl = webkitURL.createObjectURL(electedStream); RTC.attachMediaStream(largeVideoState.preload, electedStream)
largeVideoState.preload
.attr('src', electedStreamUrl);
} }
} else { } else {
...@@ -1674,7 +1714,19 @@ var VideoLayout = (function (my) { ...@@ -1674,7 +1714,19 @@ var VideoLayout = (function (my) {
endpointSimulcastLayers.forEach(function (esl) { endpointSimulcastLayers.forEach(function (esl) {
var resource = esl.endpoint; var resource = esl.endpoint;
if (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1) {
// if lastN is enabled *and* the endpoint is *not* in the lastN set,
// then ignore the event (= do not change large video/thumbnail
// SRCs).
//
// Note that even if we ignore the "changed" event in this event
// handler, the bridge must continue sending these events because
// the simulcast code in simulcast.js uses it to know what's going
// to be streamed by the bridge when/if the endpoint gets back into
// the lastN set.
if (lastNCount != -1
&& (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
return; return;
} }
...@@ -1694,21 +1746,15 @@ var VideoLayout = (function (my) { ...@@ -1694,21 +1746,15 @@ var VideoLayout = (function (my) {
var msidParts = msid.split(' '); var msidParts = msid.split(' ');
var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join('')); var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join(''));
// FIXME(gp) here we should use the VideoLayout.getPeerContainerResource var updateLargeVideo = (Strophe.getResourceFromJid(ssrc2jid[primarySSRC])
// and VideoLayout.getLargeVideoResource methods. == largeVideoState.userJid);
var updateLargeVideo = (ssrc2jid[videoSrcToSsrc[selRemoteVideo.attr('src')]] var updateFocusedVideoSrc = (focusedVideoSrc && focusedVideoSrc.src && focusedVideoSrc.src != '' &&
== ssrc2jid[videoSrcToSsrc[largeVideoState.newSrc]]); (RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoSrc.src));
// We should only update the focused video src if it's not a
// falsy value.
var updateFocusedVideoSrc
= focusedVideoSrc && focusedVideoSrc !== ''
&& (selRemoteVideo.attr('src') == focusedVideoSrc);
var electedStreamUrl; var electedStreamUrl;
if (largeVideoState.preload_ssrc == primarySSRC) if (largeVideoState.preload_ssrc == primarySSRC)
{ {
electedStreamUrl = $(largeVideoState.preload).attr('src'); RTC.setVideoSrc(selRemoteVideo[0], RTC.getVideoSrc(largeVideoState.preload[0]));
} }
else else
{ {
...@@ -1719,18 +1765,19 @@ var VideoLayout = (function (my) { ...@@ -1719,18 +1765,19 @@ var VideoLayout = (function (my) {
largeVideoState.preload_ssrc = 0; largeVideoState.preload_ssrc = 0;
electedStreamUrl = webkitURL.createObjectURL(electedStream); RTC.attachMediaStream(selRemoteVideo, electedStream);
} }
selRemoteVideo.attr('src', electedStreamUrl); var jid = ssrc2jid[primarySSRC];
videoSrcToSsrc[selRemoteVideo.attr('src')] = primarySSRC + ''; // what we store there is typeof string. jid2Ssrc[jid] = primarySSRC;
if (updateLargeVideo) { if (updateLargeVideo) {
VideoLayout.updateLargeVideo(electedStreamUrl); VideoLayout.updateLargeVideo(RTC.getVideoSrc(selRemoteVideo[0]), null,
Strophe.getResourceFromJid(jid));
} }
if (updateFocusedVideoSrc) { if (updateFocusedVideoSrc) {
focusedVideoSrc = electedStreamUrl; focusedVideoSrc.src = RTC.getVideoSrc(selRemoteVideo[0]);
} }
var videoId; var videoId;
...@@ -1854,19 +1901,25 @@ var VideoLayout = (function (my) { ...@@ -1854,19 +1901,25 @@ var VideoLayout = (function (my) {
if(this.jid==null) if(this.jid==null)
{ {
resolution = ""; resolution = "";
for(var i in this.resolution) if(this.resolution == null || !Object.keys(this.resolution)
|| Object.keys(this.resolution).length == 0)
{ {
resolutionValue = this.resolution[i]; resolution = "N/A";
if(resolutionValue) }
else
for(var i in this.resolution)
{ {
if(resolutionValue.height && resolutionValue = this.resolution[i];
resolutionValue.width) if(resolutionValue)
{ {
resolution += (resolution == ""? "" : ", ") if(resolutionValue.height &&
+ resolutionValue.width + "x" + resolutionValue.height; resolutionValue.width)
{
resolution += (resolution == ""? "" : ", ")
+ resolutionValue.width + "x" + resolutionValue.height;
}
} }
} }
}
} }
else if(!resolutionValue || else if(!resolutionValue ||
!resolutionValue.height || !resolutionValue.height ||
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<%@ page import="org.jitsi.videobridge.openfire.*" %> <%@ page import="org.jitsi.videobridge.openfire.*" %>
<%@ page import="org.jivesoftware.openfire.*" %> <%@ page import="org.jivesoftware.openfire.*" %>
<%@ page import="org.jivesoftware.util.*" %> <%@ page import="org.jivesoftware.util.*" %>
<%@ page import="java.io.File" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
...@@ -119,7 +120,13 @@ ...@@ -119,7 +120,13 @@
JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.sip.password", clientpassword); JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.sip.password", clientpassword);
String allowdirectsip = request.getParameter("allowdirectsip"); String allowdirectsip = request.getParameter("allowdirectsip");
JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.allow.direct.sip", allowdirectsip); JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.allow.direct.sip", allowdirectsip);
String recordsecret = request.getParameter("recordsecret");
JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.recording.secret", recordsecret);
String recordpath = request.getParameter("recordpath");
JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.recording.path", recordpath);
} }
%> %>
...@@ -315,7 +322,24 @@ ...@@ -315,7 +322,24 @@
<input type="radio" value="true" name="enabled" <%= ("true".equals(JiveGlobals.getProperty(PluginImpl.RECORD_PROPERTY_NAME, "false")) ? "checked" : "") %>> <input type="radio" value="true" name="enabled" <%= ("true".equals(JiveGlobals.getProperty(PluginImpl.RECORD_PROPERTY_NAME, "false")) ? "checked" : "") %>>
<b><fmt:message key="config.page.configuration.record.enabled" /></b> - <fmt:message key="config.page.configuration.record.enabled_description" /> <b><fmt:message key="config.page.configuration.record.enabled" /></b> - <fmt:message key="config.page.configuration.record.enabled_description" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.record.path"/>
</td>
<td><input type="text" size="60" maxlength="100" name="recordpath"
value="<%= JiveGlobals.getProperty("org.jitsi.videobridge.ofmeet.recording.path", container.pluginDirectory.getAbsolutePath() + File.separator + "recordings") %>">
</td>
</tr>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.record.secret"/>
</td>
<td><input type="password" size="60" maxlength="100" name="recordsecret"
value="<%= JiveGlobals.getProperty("org.jitsi.videobridge.ofmeet.recording.secret", "secret") %>">
</td>
</tr>
</tbody> </tbody>
</table> </table>
</p> </p>
...@@ -350,7 +374,7 @@ ...@@ -350,7 +374,7 @@
<td align="left" width="150"> <td align="left" width="150">
<fmt:message key="config.page.configuration.server"/> <fmt:message key="config.page.configuration.server"/>
</td> </td>
<td><input type="text" size="20" maxlength="100" name="server" <td><input type="text" size="40" maxlength="100" name="server"
value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.sipserver", "") %>"> value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.sipserver", "") %>">
</td> </td>
</tr> </tr>
...@@ -359,7 +383,7 @@ ...@@ -359,7 +383,7 @@
<td align="left" width="150"> <td align="left" width="150">
<fmt:message key="config.page.configuration.outboundproxy"/> <fmt:message key="config.page.configuration.outboundproxy"/>
</td> </td>
<td><input type="text" size="20" maxlength="100" name="outboundproxy" <td><input type="text" size="40" maxlength="100" name="outboundproxy"
value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.outboundproxy", "") %>"> value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.outboundproxy", "") %>">
</td> </td>
</tr> </tr>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment