Commit aceb7499 authored by Dele Olajide's avatar Dele Olajide

ofmeet plugin - work in progress

parent 565460cb
......@@ -49,6 +49,14 @@
Openfire Meetings Plugin Changelog
</h1>
<p><b>0.0.3</b> -- Dec 2nd, 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>Latest version of Jitsi Meet</li>
</ul>
<p><b>0.0.2</b> -- Nov 30th, 2014</p>
<ul>
......
......@@ -5,9 +5,9 @@
<name>ofmeet</name>
<description>Openfire Meetings</description>
<author></author>
<version>0.0.2</version>
<version>0.0.3</version>
<date>11/30/2014</date>
<minServerVersion>3.10.0</minServerVersion>
<minServerVersion>3.9.9</minServerVersion>
<adminconsole>
<tab id="tab-ofmeet" name="${plugin.title}" url="ofmeet-summary.jsp" description="${plugin.description}">
......
......@@ -11,8 +11,12 @@ var recordingToken ='';
var roomUrl = null;
var roomName = null;
var ssrc2jid = {};
var mediaStreams = [];
var mediaStreams = {};
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.
......@@ -31,7 +35,6 @@ var localStatsCollector = null;
* FIXME: remove those maps
*/
var ssrc2videoType = {};
var videoSrcToSsrc = {};
/**
* Currently focused video "src"(displayed in large video).
* @type {String}
......@@ -65,26 +68,43 @@ function init() {
if (RTC === null) {
window.location.href = 'webrtcrequired.html';
return;
} else if (RTC.browser !== 'chrome') {
} else if (RTC.browser !== 'chrome' &&
config.enableFirefoxSupport !== true) {
window.location.href = 'chromeonly.html';
return;
}
obtainAudioAndVideoPermissions(function (stream) {
var audioStream = new webkitMediaStream();
var videoStream = new webkitMediaStream();
var audioTracks = stream.getAudioTracks();
var videoTracks = stream.getVideoTracks();
for (var i = 0; i < audioTracks.length; i++) {
audioStream.addTrack(audioTracks[i]);
var audioStream, videoStream;
if(window.webkitMediaStream)
{
var audioStream = new webkitMediaStream();
var videoStream = new webkitMediaStream();
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);
startLocalRtpStatsCollector(audioStream);
else
{
VideoLayout.changeLocalStream(stream);
startLocalRtpStatsCollector(stream);
for (i = 0; i < videoTracks.length; i++) {
videoStream.addTrack(videoTracks[i]);
}
VideoLayout.changeLocalVideo(videoStream, true);
maybeDoJoin();
});
......@@ -106,13 +126,20 @@ function connect(jid, password) {
localAudio = connection.jingle.localAudio;
localVideo = connection.jingle.localVideo;
}
// BAO
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); };
if (nickname) {
connection.emuc.addDisplayNameToPresence(nickname);
var email = SettingsMenu.getEmail();
var displayName = SettingsMenu.getDisplayName();
if(email) {
connection.emuc.addEmailToPresence(email);
} else {
connection.emuc.addUserIdToPresence(SettingsMenu.getUID());
}
if(displayName) {
connection.emuc.addDisplayNameToPresence(displayName);
}
if (connection.disco) {
......@@ -167,24 +194,33 @@ function connect(jid, password) {
*/
function obtainAudioAndVideoPermissions(callback) {
// 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(
['audio', 'video'],
function (avStream) {
callback(avStream);
trackUsage('localMedia', {
audio: avStream.getAudioTracks().length,
video: avStream.getVideoTracks().length
});
},
cb,
function (error) {
console.error('failed to obtain audio/video stream - stop', error);
trackUsage('localMediaError', {
media: error.media || 'video',
name : error.name
});
messageHandler.showError("Error",
"Failed to obtain permissions to use the local microphone" +
"and/or camera.");
console.error('failed to obtain audio/video stream - trying audio only', error);
getUserMediaWithConstraints(
['audio'],
cb,
function (error) {
console.error('failed to obtain audio/video stream - stop', error);
trackUsage('localMediaError', {
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');
}
......@@ -250,8 +286,7 @@ function doJoin() {
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
// to the RTC.attachMediaStream() function but that call is *not* followed
// by an update to the videoSrcToSsrc map!
......@@ -283,17 +318,17 @@ function waitForRemoteVideo(selector, ssrc, stream) {
// 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
if (ssrc && selector.attr('src')) {
videoSrcToSsrc[selector.attr('src')] = ssrc;
if (ssrc && jid) {
jid2Ssrc[Strophe.getResourceFromJid(jid)] = ssrc;
} else {
console.warn("No ssrc given for video", selector);
messageHandler.showError('Warning', 'No ssrc was given for the video.');
console.warn("No ssrc given for jid", jid);
// messageHandler.showError('Warning', 'No ssrc was given for the video.');
}
$(document).trigger('videoactive.jingle', [selector]);
} else {
setTimeout(function () {
waitForRemoteVideo(selector, ssrc, stream);
waitForRemoteVideo(selector, ssrc, stream, jid);
}, 250);
}
}
......@@ -306,16 +341,19 @@ function waitForPresence(data, sid) {
var sess = connection.jingle.sessions[sid];
var thessrc;
// 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
var ssrclines
= SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc:');
ssrclines = ssrclines.filter(function (line) {
// NOTE(gp) previously we filtered on the mslabel, but that property
// is not always present.
// 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) {
thessrc = ssrclines[0].substring(7).split(' ')[0];
......@@ -345,10 +383,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
// ssrc. We should probably take that into account in our MediaStream
// 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 remotes = document.getElementById('remoteVideos');
......@@ -396,25 +460,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
function sendKeyframe(pc) {
console.log('sendkeyframe', pc.iceConnectionState);
......@@ -623,15 +668,27 @@ $(document).bind('setLocalDescription.jingle', function (event, sid) {
var media = simulcast.parseMedia(sess.peerconnection.localDescription);
media.forEach(function (media) {
// TODO(gp) maybe exclude FID streams?
Object.keys(media.sources).forEach(function(ssrc) {
if(Object.keys(media.sources).length > 0) {
// 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({
'ssrc': ssrc,
'ssrc': sess.localStreamsSSRC[media.type],
'type': media.type,
'direction': media.direction
});
});
}
});
console.log('new ssrcs', newssrcs);
// Have to clear presence map to get rid of removed streams
......@@ -664,20 +721,22 @@ $(document).bind('iceconnectionstatechange.jingle', function (event, sid, sessio
var metadata = {};
metadata.setupTime = (new Date()).getTime() - session.timeChecking;
session.peerconnection.getStats(function (res) {
res.result().forEach(function (report) {
if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') {
metadata.localCandidateType = report.stat('googLocalCandidateType');
metadata.remoteCandidateType = report.stat('googRemoteCandidateType');
if(res && res.result) {
res.result().forEach(function (report) {
if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') {
metadata.localCandidateType = report.stat('googLocalCandidateType');
metadata.remoteCandidateType = report.stat('googRemoteCandidateType');
// log pair as well so we can get nice pie charts
metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType');
// log pair as well so we can get nice pie charts
metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType');
if (report.stat('googRemoteAddress').indexOf('[') === 0) {
metadata.ipv6 = true;
if (report.stat('googRemoteAddress').indexOf('[') === 0) {
metadata.ipv6 = true;
}
}
}
});
trackUsage('iceConnected', metadata);
});
trackUsage('iceConnected', metadata);
}
});
}
break;
......@@ -712,7 +771,7 @@ $(document).bind('joined.muc', function (event, jid, info) {
VideoLayout.showFocusIndicator();
// 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
ToolbarToggler.showToolbar();
......@@ -734,7 +793,12 @@ $(document).bind('entered.muc', function (event, jid, info, pres) {
console.log('is focus? ' + (focus ? 'true' : 'false'));
// 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"))
{
......@@ -785,14 +849,13 @@ $(document).bind('left.muc', function (event, jid) {
APIConnector.triggerEvent("participantLeft",{jid: jid});
}
delete jid2Ssrc[jid];
// 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);
......@@ -844,8 +907,6 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
Object.keys(ssrc2jid).forEach(function (ssrc) {
if (ssrc2jid[ssrc] == jid) {
delete ssrc2jid[ssrc];
}
if (ssrc2videoType[ssrc] == jid) {
delete ssrc2videoType[ssrc];
}
});
......@@ -854,6 +915,7 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
//console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
var ssrcV = ssrc.getAttribute('ssrc');
ssrc2jid[ssrcV] = jid;
notReceivedSSRCs.push(ssrcV);
var type = ssrc.getAttribute('type');
ssrc2videoType[ssrcV] = type;
......@@ -892,6 +954,13 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
"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) {
......@@ -959,16 +1028,20 @@ $(document).bind('passwordrequired.main', function (event) {
* blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395
* @returns {boolean}
*/
function isVideoSrcDesktop(videoSrc) {
function isVideoSrcDesktop(jid) {
// FIXME: fix this mapping mess...
// figure out if large video is desktop stream or just a camera
if(!jid)
return false;
var isDesktop = false;
if (localVideoSrc === videoSrc) {
if (connection.emuc.myroomjid &&
Strophe.getResourceFromJid(connection.emuc.myroomjid) === jid) {
// local video
isDesktop = isUsingScreenStream;
} else {
// Do we have associations...
var videoSsrc = videoSrcToSsrc[videoSrc];
var videoSsrc = jid2Ssrc[jid];
if (videoSsrc) {
var videoType = ssrc2videoType[videoSsrc];
if (videoType) {
......@@ -978,7 +1051,7 @@ function isVideoSrcDesktop(videoSrc) {
console.error("No video type for ssrc: " + videoSsrc);
}
} else {
console.error("No ssrc for src: " + videoSrc);
console.error("No ssrc for jid: " + jid);
}
}
return isDesktop;
......@@ -1346,6 +1419,8 @@ $(document).ready(function () {
VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
});
document.getElementById('largeVideo').volume = 0;
if (!$('#settings').is(':visible')) {
console.log('init');
init();
......@@ -1371,22 +1446,44 @@ $(document).ready(function () {
"showMethod": "fadeIn",
"hideMethod": "fadeOut",
"reposition": function() {
if(Chat.isVisible() || ContactList.isVisible()) {
$("#toast-container").addClass("toast-bottom-right-center");
if(PanelToggler.isVisible()) {
$("#toast-container").addClass("notification-bottom-right-center");
} else {
$("#toast-container").removeClass("toast-bottom-right-center");
$("#toast-container").removeClass("notification-bottom-right-center");
}
},
"newestOnTop": false
}
};
$('#settingsmenu>input').keyup(function(event){
if(event.keyCode === 13) {//enter
SettingsMenu.update();
}
})
});
$(window).bind('beforeunload', function () {
if (connection && connection.connected) {
connection.send($pres({type: "unavailable"})) // BAO
connection.disconnect();
// ensure signout
$.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);
if(APIConnector.isEnabled())
......@@ -1399,10 +1496,10 @@ function disposeConference(onUnload) {
// FIXME: probably removing streams is not required and close() should
// be enough
if (connection.jingle.localAudio) {
handler.peerconnection.removeStream(connection.jingle.localAudio);
handler.peerconnection.removeStream(connection.jingle.localAudio, onUnload);
}
if (connection.jingle.localVideo) {
handler.peerconnection.removeStream(connection.jingle.localVideo);
handler.peerconnection.removeStream(connection.jingle.localVideo, onUnload);
}
handler.peerconnection.close();
}
......@@ -1562,7 +1659,7 @@ function onSelectedEndpointChanged(userJid)
dataChannel.send(JSON.stringify({
'colibriClass': 'SelectedEndpointChangedEvent',
'selectedEndpoint': (!userJid || userJid == null)
? null : Strophe.getResourceFromJid(userJid)
? null : userJid
}));
return true;
......@@ -1630,7 +1727,7 @@ function callSipButtonClicked()
document.getElementById('sipNumber').focus();
}
);
}
}
}
function hangup() {
......@@ -1665,3 +1762,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);
}
}
});
......@@ -122,7 +122,16 @@ var Avatar = (function(my) {
}
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 mediaStreams[jid][MediaStream.VIDEO_TYPE].muted;
......@@ -132,6 +141,9 @@ var Avatar = (function(my) {
if(id === connection.emuc.myroomjid || !id) {
id = SettingsMenu.getUID();
}
if (config.userAvatar && config.userAvatar != "null") return config.userAvatar; // BAO
return 'https://www.gravatar.com/avatar/' +
MD5.hexdigest(id.trim().toLowerCase()) +
"?d=retro&size=" + (size || "30");
......
var BottomToolbar = (function (my) {
my.toggleChat = function() {
if (ContactList.isVisible()) {
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");
PanelToggler.toggleChat();
};
my.toggleContactList = function() {
if (Chat.isVisible()) {
buttonClick("#chatBottomButton", "active");
setTimeout(function() {
$('#chatspace').css('display', 'none');
}, 500);
}
buttonClick("#contactListButton", "active");
ContactList.toggleContactList();
PanelToggler.toggleContactList();
};
my.toggleFilmStrip = function() {
......
......@@ -57,7 +57,7 @@ var Chat = (function (my) {
var onTextAreaResize = function () {
resizeChatConversation();
scrollChatToBottom();
Chat.scrollChatToBottom();
};
$('#usermsg').autosize({callback: onTextAreaResize});
......@@ -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.
......@@ -268,7 +163,7 @@ var Chat = (function (my) {
* Resizes the chat area.
*/
my.resizeChat = function () {
var chatSize = Chat.getChatSize();
var chatSize = PanelToggler.getPanelSize();
$('#chatspace').width(chatSize[0]);
$('#chatspace').height(chatSize[1]);
......@@ -276,20 +171,6 @@ var Chat = (function (my) {
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.
*/
......@@ -309,6 +190,16 @@ var Chat = (function (my) {
$('#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
*/
......@@ -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
......
......@@ -44,5 +44,7 @@ var config = {
useBundle: true,
enableRecording: false,
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) {
* Adds a contact for the given peerJid if such doesn't yet exist.
*
* @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 contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if (!contact || contact.length <= 0)
ContactList.addContact(peerJid);
ContactList.addContact(peerJid,id);
};
/**
* Adds a contact for the given peer jid.
*
* @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 contactlist = $('#contactlist>ul');
......@@ -51,7 +53,7 @@ var ContactList = (function (my) {
}
};
newContact.appendChild(createAvatar());
newContact.appendChild(createAvatar(id));
newContact.appendChild(createDisplayNameParagraph("Participant"));
var clElement = contactlist.get(0);
......@@ -87,95 +89,27 @@ var ContactList = (function (my) {
}
};
/**
* Opens / closes the contact list area.
*/
my.toggleContactList = function () {
var contactlist = $('#contactlist');
var videospace = $('#videospace');
var chatSize = (ContactList.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 = 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});
my.setVisualNotification = function(show, stopGlowingIn) {
var glower = $('#contactListButton');
function stopGlowing() {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('glowing');
if(!ContactList.isVisible()) {
glower.removeClass('active');
}
}
//stop the glowing of the contact list icon
setVisualNotification(false);
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
stopGlowing();
}
if(stopGlowingIn) {
setTimeout(stopGlowing, stopGlowingIn);
}
};
......@@ -191,20 +125,21 @@ var ContactList = (function (my) {
$("#numberOfParticipants").text('');
numberOfContacts += delta;
} else if(numberOfContacts !== 0 && !ContactList.isVisible()) {
setVisualNotification(true);
ContactList.setVisualNotification(true);
numberOfContacts += delta;
$("#numberOfParticipants").text(numberOfContacts);
}
};
}
/**
* Creates the avatar element.
*
* @return the newly created avatar element
*/
function createAvatar() {
var avatar = document.createElement('i');
function createAvatar(id) {
var avatar = document.createElement('img');
avatar.className = "icon-avatar avatar";
avatar.src = "https://www.gravatar.com/avatar/" + id + "?d=retro&size=30";
return avatar;
}
......@@ -221,33 +156,6 @@ var ContactList = (function (my) {
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.
......
......@@ -34,6 +34,7 @@
margin-right: 10px;
vertical-align: middle;
font-size: 22pt;
border-radius: 20px;
}
#contactlist .clickable {
......
......@@ -112,4 +112,8 @@
.icon-connection:before {
line-height: normal;
content: "\e61a";
}
.icon-settings:before {
content: "\e61b";
}
\ No newline at end of file
......@@ -13,8 +13,7 @@ html, body{
overflow-x: hidden;
}
#chatspace,
#contactlist {
.right-panel {
display:none;
position:absolute;
float: right;
......@@ -38,10 +37,6 @@ html, body{
display:none;
}
#settingsButton {
visibility: hidden;
}
.toolbar_span {
display: inline-block;
position: relative;
......
......@@ -35,7 +35,9 @@
#remoteVideos .videocontainer {
display: inline-block;
background-image:url(../images/avatar1.png);
background-color: black;
background-repeat: no-repeat;
background-position: 45;
background-size: contain;
border-radius:8px;
border: 2px solid #212425;
......@@ -102,6 +104,11 @@
text-align: center;
}
#largeVideo
{
object-fit: cover;
}
#presentation,
#etherpad,
#localVideoWrapper>video,
......@@ -115,10 +122,6 @@
height: 100%;
}
.dominantspeaker {
background: #000 !important;
}
#etherpad,
#presentation {
text-align: center;
......@@ -378,3 +381,19 @@
#mixedstream {
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)
// when the data channel becomes available, tell the bridge about video
// selections so that it can do adaptive simulcast,
var largeVideoSrc = $('#largeVideo').attr('src');
var userJid = getJidFromVideoSrc(largeVideoSrc);
var userJid = VideoLayout.getLargeVideoState().userJid;
// we want the notification to trigger even if userJid is undefined,
// or null.
onSelectedEndpointChanged(userJid);
......
......@@ -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="&#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="&#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>
\ No newline at end of file
{
"IcoMoonType": "selection",
"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": {
"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",
"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": [
{
"opacity": 1,
......@@ -17,11 +51,10 @@
"visibility": false
}
],
"width": 1334,
"grid": 0,
"tags": [
"webCam"
]
],
"grid": 0
},
"attrs": [
{
......@@ -714,7 +747,7 @@
"ligatures": ""
},
"setIdx": 0,
"iconIdx": 26
"iconIdx": 25
},
{
"icon": {
......@@ -740,7 +773,7 @@
"ligatures": ""
},
"setIdx": 0,
"iconIdx": 27
"iconIdx": 26
},
{
"icon": {
......@@ -765,7 +798,7 @@
"ligatures": ""
},
"setIdx": 0,
"iconIdx": 28
"iconIdx": 27
}
],
"height": 1024,
......@@ -775,6 +808,7 @@
"preferences": {
"showGlyphs": true,
"showQuickUse": true,
"showQuickUse2": true,
"showSVGs": true,
"fontPref": {
"prefix": "icon-",
......@@ -791,7 +825,8 @@
},
"imagePref": {
"prefix": "icon-",
"png": true
"png": true,
"useClassSelector": true
},
"historySize": 100,
"showCodes": true,
......
......@@ -55,6 +55,8 @@ config.page.configuration.audiomixer.enabled=Enabled
config.page.configuration.audiomixer.disabled=Disbled
config.page.configuration.audiomixer.enabled_description=Audio Mixer enabled
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.expired=Conference has been expired.
ofmeet.summary.conferences=Total Conferences
......
......@@ -12,9 +12,9 @@
<script src="libs/jquery-2.1.1.min.js"></script>
<script src="/ofmeet/config"></script><!-- BAO -->
<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.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.workgroup.js?v=1"></script><!-- BAO -->
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
......@@ -31,18 +31,19 @@
<script src="libs/rayo.js?v=1"></script>
<script src="libs/tooltip.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="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="estos_log.js?v=2"></script><!-- simple stanza logger -->
<script src="ofmeet-screenshare.js?v=1"></script><!-- BAO -->
<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="chat.js?v=14"></script><!-- chat logic -->
<script src="contact_list.js?v=6"></script><!-- contact list logic -->
<script src="util.js?v=6"></script><!-- utility functions -->
<script src="chat.js?v=15"></script><!-- chat logic -->
<script src="contact_list.js?v=7"></script><!-- contact list logic -->
<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="prezi.js?v=6"></script><!-- prezi plugin -->
<script src="smileys.js?v=3"></script><!-- smiley images -->
......@@ -51,33 +52,36 @@
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<script src="rtp_sts.js?v=5"></script><!-- RTP 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="toolbar.js?v=6"></script><!-- toolbar ui -->
<script src="toolbar_toggler.js?v=2"></script>
<script src="canvas_util.js?v=1"></script><!-- canvas drawing utils -->
<script src="audio_levels.js?v=2"></script><!-- audio levels plugin -->
<script src="media_stream.js?v=1"></script><!-- media stream -->
<script src="bottom_toolbar.js?v=5"></script><!-- media stream -->
<script src="media_stream.js?v=2"></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="keyboard_shortcut.js?v=3"></script>
<script src="tracking.js?v=1"></script><!-- tracking -->
<script src="jitsipopover.js?v=3"></script>
<script src="message_handler.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">
<link rel="stylesheet" href="css/font.css?v=5"/>
<script src="settings_menu.js?v=1"></script>
<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" type="text/css" media="screen" href="css/main.css?v=29"/>
<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/main.css?v=30"/>
<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/modaldialog.css?v=3">
<link rel="stylesheet" href="css/popup_menu.css?v=4">
<link rel="stylesheet" href="css/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/welcome_page.css?v=2">
<link rel="stylesheet" href="css/settingsmenu.css?v=1">
<!--
Link used for inline installation of chrome desktop streaming extension,
is updated automatically from the code with the value defined in config.js -->
......@@ -237,6 +241,10 @@
<i class="icon-telephone"></i></a>
</span>
<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">
<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>
......@@ -263,6 +271,7 @@
<a target="_new"><div class="watermark leftwatermark"></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>
<img id="activeSpeakerAvatar" src=""/>
<video id="largeVideo" autoplay oncontextmenu="return false;"></video>
</div>
<div id="remoteVideos">
......@@ -306,7 +315,7 @@
</span>
</span>
</div>
<div id="chatspace">
<div id="chatspace" class="right-panel">
<div id="nickname">
Enter a nickname in the box below
<form>
......@@ -324,11 +333,19 @@
</div>
</div>
</div>
<div id="contactlist">
<div id="contactlist" class="right-panel">
<ul>
<li class="title"><i class="icon-contact-list"></i> CONTACT LIST</li>
</ul>
</div>
<div id="settingsmenu" class="right-panel">
<div class="icon-settings"> SETTINGS</div>
<img id="avatar" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD6E+LPjLUNIuoPD2izLbaldQ+cbl4wwijyVG0EY3EgnJyBt5BzXkFl4k1u08YbLy6+1Xsrgx3vCyR/Lg5CDDD2469cZpnxy8ZWWs+O0l0XfjT4TZSTk7TK6yNu2jOCoPAPUlm7AZr/AApv7S5vr2+v42eUBMeYBuQfMDx2ydtfEZti5yru0tFt5Hv5c6Ps1H7TPVE8Ya3F5Miasblo2HmQSQJFvHocqCoPTNehaFr1vqllBdQnCzoHCsMEZHSvAvGWsW9rBPfwyiAIMI5HGTnHQ1u/BrxWNWsUUFUkt2Ecsa5wvGRjPPT9QR2r0OH8TWrSm5yvHpfv/kGa4JU6SqRjbuec+Ofhb4r0PWbtYbZryxHzQ3aFAsi5OAVLZDAAZGMdwTzXEWN7PpmpGVPkuomKvjg7u6ntkdK+5NasFvLZkPGVIrxXxl8INKu72a+imubaSQgsI9hUnjnDIcH6V9NleEweEqznUhzcys76o+XxVOpOzpys0eS/FLVtP1PxTJY6YJF0yNkjgkJMhb5Qd4Dcg5bp7YrqPgbZ3NhCLyVgTdRptUfwqC5HPvv6emKkf4WWqThpbm5mVT90xxKG9jhBXoHhDw99nMSLGkaJgAAYwOa7MS8K4xjh4W5fK33muGq4qMZxqTupWb9Uf//Z"/> <!-- 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>
</div>
</body>
......
......@@ -6,11 +6,13 @@ var interfaceConfig = {
TOOLBAR_TIMEOUT: 4000,
DEFAULT_REMOTE_DISPLAY_NAME: "Change Me",
DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME: "Speaker",
DEFAULT_LOCAL_DISPLAY_NAME: "me",
SHOW_JITSI_WATERMARK: false,
JITSI_WATERMARK_LINK: "",
SHOW_BRAND_WATERMARK: false,
BRAND_WATERMARK_LINK: "",
SHOW_POWERED_BY: false,
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
APP_NAME: "Openfire Meetings"
APP_NAME: "Openfire Meetings",
ACTIVE_SPEAKER_AVATAR_SIZE: 100
};
......@@ -9,6 +9,7 @@ package org.jitsi.videobridge.openfire;
import org.jivesoftware.util.*;
import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.vcard.VCardManager;
import org.slf4j.*;
import org.slf4j.Logger;
......@@ -25,6 +26,8 @@ import java.util.*;
import java.text.*;
import java.security.Principal;
import org.dom4j.*;
public class Config extends HttpServlet
{
......@@ -38,12 +41,27 @@ public class Config extends HttpServlet
String hostname = XMPPServer.getInstance().getServerInfo().getHostname();
String domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
String userName = "null";
String userAvatar = "null";
String securityEnabled = JiveGlobals.getProperty("ofmeet.security.enabled", "true");
if ("true".equals(securityEnabled))
{
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;
}
}
}
boolean nodejs = XMPPServer.getInstance().getPluginManager().getPlugin("nodejs") != null;
......@@ -126,6 +144,7 @@ public class Config extends HttpServlet
out.println(" audioBandwidth: '" + audioBandwidth + "',");
out.println(" videoBandwidth: '" + videoBandwidth + "',");
out.println(" userName: '" + userName + "',");
out.println(" userAvatar: '" + userAvatar + "',");
out.println(" disablePrezi: true,");
out.println(" bosh: window.location.protocol + '//' + window.location.host + '/http-bind/'");
out.println("}; ");
......
......@@ -56,7 +56,7 @@ public class OfMeetPlugin implements Plugin, ClusterEventListener {
private PluginImpl jitsiPlugin;
private JigasiPlugin jigasiPlugin;
private PluginManager manager;
private File pluginDirectory;
public File pluginDirectory;
public String sipRegisterStatus = "";
......
......@@ -462,7 +462,8 @@ ColibriFocus.prototype.createdConference = function (result) {
'a=rtpmap:100 VP8/90000\r\n' +
'a=rtcp-fb:100 ccm fir\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:117 ulpfec/90000\r\n' +
(config.useRtcpMux ? 'a=rtcp-mux\r\n' : '') +
......
......@@ -34,7 +34,7 @@
try {
message = JSON.parse(event.data);
} 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 (console && console.log) console.log('received', message);
}
......
......@@ -46,9 +46,9 @@ Strophe.addConnectionPlugin('rayo',
console.info('Dial result ', result);
var resource = $(result).find('ref').attr('uri');
self.call_resource = resource.substr('xmpp:'.length);
this.call_resource = resource.substr('xmpp:'.length);
console.info(
"Received call resource: " + self.call_resource);
"Received call resource: " + this.call_resource);
},
function (error)
{
......
......@@ -141,12 +141,28 @@ if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
TraceablePeerConnection.prototype.addStream = function (stream) {
this.trace('addStream', stream.id);
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);
simulcast.resetSender();
if(stopStreams) {
stream.getAudioTracks().forEach(function (track) {
track.stop();
});
stream.getVideoTracks().forEach(function (track) {
track.stop();
});
}
this.peerconnection.removeStream(stream);
};
......@@ -477,6 +493,11 @@ TraceablePeerConnection.prototype.addIceCandidate = function (candidate, success
TraceablePeerConnection.prototype.getStats = function(callback, errback) {
if (navigator.mozGetUserMedia) {
// ignore for now...
if(!errback)
errback = function () {
}
this.peerconnection.getStats(null,callback,errback);
} else {
this.peerconnection.getStats(callback);
}
......@@ -497,7 +518,40 @@ function setupRTC() {
element[0].mozSrcObject = stream;
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)
MediaStream.prototype.getVideoTracks = function () { return []; };
......@@ -516,7 +570,19 @@ function setupRTC() {
element.attr('src', webkitURL.createObjectURL(stream));
},
// 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) {
RTC.pc_constraints = {}; // disable DTLS on Android
......
......@@ -84,7 +84,9 @@ Strophe.addConnectionPlugin('jingle', {
case 'session-initiate':
sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection);
// configure session
if (this.localAudio) {
//in firefox we have only one stream object
if (this.localAudio != this.localVideo) {
sess.localStreams.push(this.localAudio);
}
if (this.localVideo) {
......@@ -169,7 +171,9 @@ Strophe.addConnectionPlugin('jingle', {
Math.random().toString(36).substr(2, 12), // random string
this.connection);
// configure session
if (this.localAudio) {
//in firefox we have only one stream
if (this.localAudio != this.localVideo) {
sess.localStreams.push(this.localAudio);
}
if (this.localVideo) {
......
......@@ -194,7 +194,8 @@ SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
}
// 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 self = this;
// new bundle plan
......@@ -221,7 +222,12 @@ SDP.prototype.toJingle = function (elem, thecreator) {
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
} else {
ssrc = false;
if(ssrcs && ssrcs[mline.media])
{
ssrc = ssrcs[mline.media];
}
else
ssrc = false;
}
elem.c('content', {creator: thecreator, name: mline.media});
......@@ -267,25 +273,60 @@ SDP.prototype.toJingle = function (elem, thecreator) {
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
// FIXME: group by ssrc and support multiple different ssrcs
var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:');
ssrclines.forEach(function(line) {
idx = line.indexOf(' ');
var linessrc = line.substr(0, idx).substr(7);
if (linessrc != ssrc) {
if(ssrclines.length > 0) {
ssrclines.forEach(function (line) {
idx = line.indexOf(' ');
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();
ssrc = linessrc;
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
}
var kv = line.substr(idx + 1);
});
elem.up();
}
else
{
elem.up();
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
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.attrs({name: "cname", value:Math.random().toString(36).substring(7)});
elem.up();
});
elem.up();
var msid = null;
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
var ssrc_group_lines = SDPUtil.find_lines(this.media[i], 'a=ssrc-group:');
......
......@@ -36,6 +36,7 @@ function JingleSession(me, sid, connection) {
this.reason = null;
this.wait = true;
this.localStreamsSSRC = null;
}
JingleSession.prototype.initiate = function (peerjid, isInitiator) {
......@@ -64,6 +65,7 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
};
this.peerconnection.onaddstream = function (event) {
self.remoteStreams.push(event.stream);
console.log("REMOTE STREAM ADDED: " + event.stream + " - " + event.stream.id);
$(document).trigger('remotestreamadded.jingle', [event, self.sid]);
};
this.peerconnection.onremovestream = function (event) {
......@@ -128,7 +130,7 @@ JingleSession.prototype.accept = function () {
initiator: this.initiator,
responder: this.responder,
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,
function () {
var ack = {};
......@@ -219,10 +221,10 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
}, 20);
}
this.drip_container.push(event.candidate);
this.drip_container.push(candidate);
return;
} else {
self.sendIceCandidate([event.candidate]);
self.sendIceCandidate([candidate]);
}
}
} else {
......@@ -236,25 +238,43 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
initiator: this.initiator,
sid: this.sid});
this.localSDP = new SDP(this.peerconnection.localDescription.sdp);
this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder');
this.connection.sendIQ(init,
function () {
//console.log('session initiate ack');
var ack = {};
ack.source = 'offer';
$(document).trigger('ack.jingle', [self.sid, ack]);
},
function (stanza) {
self.state = 'error';
self.peerconnection.close();
var error = ($(stanza).find('error').length) ? {
code: $(stanza).find('error').attr('code'),
reason: $(stanza).find('error :first')[0].tagName,
}:{};
error.source = 'offer';
$(document).trigger('error.jingle', [self.sid, error]);
},
10000);
var self = this;
var sendJingle = function (ssrc) {
if(!ssrc)
ssrc = {};
self.localSDP.toJingle(init, self.initiator == self.me ? 'initiator' : 'responder', ssrc);
self.connection.sendIQ(init,
function () {
//console.log('session initiate ack');
var ack = {};
ack.source = 'offer';
$(document).trigger('ack.jingle', [self.sid, ack]);
},
function (stanza) {
self.state = 'error';
self.peerconnection.close();
var error = ($(stanza).find('error').length) ? {
code: $(stanza).find('error').attr('code'),
reason: $(stanza).find('error :first')[0].tagName,
}:{};
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;
console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate);
......@@ -275,11 +295,12 @@ JingleSession.prototype.sendIceCandidates = function (candidates) {
sid: this.sid});
for (var mid = 0; mid < this.localSDP.media.length; 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) {
var ice = SDPUtil.iceparams(this.localSDP.media[mid], this.localSDP.session);
ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
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);
for (var i = 0; i < cands.length; i++) {
cand.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up();
......@@ -338,14 +359,14 @@ JingleSession.prototype.createdOffer = function (sdp) {
var self = this;
this.localSDP = new SDP(sdp.sdp);
//this.localSDP.mangle();
if (this.usetrickle) {
var sendJingle = function () {
var init = $iq({to: this.peerjid,
type: 'set'})
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
action: 'session-initiate',
initiator: this.initiator,
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,
function () {
var ack = {};
......@@ -367,7 +388,16 @@ JingleSession.prototype.createdOffer = function (sdp) {
sdp.sdp = this.localSDP.raw;
this.peerconnection.setLocalDescription(sdp,
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');
},
function (e) {
......@@ -558,33 +588,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
//this.localSDP.mangle();
this.usepranswer = provisional === true;
if (this.usetrickle) {
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 {
if (this.usepranswer) {
sdp.type = 'pranswer';
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');
......@@ -592,11 +596,48 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
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;
this.peerconnection.setLocalDescription(sdp,
function () {
$(document).trigger('setLocalDescription.jingle', [self.sid]);
//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) {
console.error('setLocalDescription failed', e);
......
......@@ -82,14 +82,17 @@ SessionBase.prototype.switchStreams = function (new_stream, oldStream, success_c
if(self.peerconnection.localDescription) {
oldSdp = new SDP(self.peerconnection.localDescription.sdp);
}
self.peerconnection.removeStream(oldStream);
self.peerconnection.removeStream(oldStream, true);
self.peerconnection.addStream(new_stream);
}
self.connection.jingle.localVideo = new_stream;
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);
// 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() {
* @constructor
*/
function MediaStreamProto(data, sid, ssrc) {
this.VIDEO_TYPE = "Video";
this.AUDIO_TYPE = "Audio";
this.stream = data.stream;
this.peerjid = data.peerjid;
this.ssrc = ssrc;
this.session = connection.jingle.sessions[sid];
this.type = (this.stream.getVideoTracks().length > 0)
? this.VIDEO_TYPE : this.AUDIO_TYPE;
? MediaStream.VIDEO_TYPE : MediaStream.AUDIO_TYPE;
this.muted = false;
}
return MediaStreamProto;
})();
\ No newline at end of file
})();
MediaStream.VIDEO_TYPE = 'Video';
MediaStream.AUDIO_TYPE = 'Audio';
\ No newline at end of file
......@@ -111,7 +111,7 @@ Strophe.addConnectionPlugin('emuc', {
var create = $iq({type: 'set', to: this.roomjid})
.c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
.c('x', {xmlns: 'jabber:x:data', type: 'submit'});
this.connection.send(create); // fire away
this.connection.sendIQ(create); // fire away
}
// Parse roles.
......@@ -335,6 +335,14 @@ Strophe.addConnectionPlugin('emuc', {
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']) {
// XEP-0172
pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'})
......@@ -456,5 +464,11 @@ Strophe.addConnectionPlugin('emuc', {
},
addBridgeIsDownToPresence: function() {
this.presMap['bridgeIsDown'] = true;
},
addEmailToPresence: function(email) {
this.presMap['email'] = email;
},
addUserIdToPresence: function(userId) {
this.presMap['userId'] = userId;
}
});
......@@ -79,7 +79,14 @@ PeerStats.prototype.setSsrcResolution = function (ssrc, resolution)
*/
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)
*/
PeerStats.transport = [];
/**
* <tt>StatsCollector</tt> registers for stats updates of given
* <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular
......@@ -174,7 +182,15 @@ StatsCollector.prototype.start = function ()
self.peerconnection.getStats(
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);
self.currentAudioLevelsReport = results;
self.processAudioLevelReport();
......@@ -193,10 +209,28 @@ StatsCollector.prototype.start = function ()
self.peerconnection.getStats(
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);
self.currentStatsReport = results;
self.processStatsReport();
try
{
self.processStatsReport();
}
catch(e)
{
console.error("Unsupported key:" + e);
}
self.baselineStatsReport = self.currentStatsReport;
},
self.errorCallback
......@@ -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.
......@@ -217,23 +281,29 @@ StatsCollector.prototype.processStatsReport = function () {
for (var idx in this.currentStatsReport) {
var now = this.currentStatsReport[idx];
if (now.stat('googAvailableReceiveBandwidth') ||
now.stat('googAvailableSendBandwidth'))
{
PeerStats.bandwidth = {
"download": Math.round(
(now.stat('googAvailableReceiveBandwidth')) / 1000),
"upload": Math.round(
(now.stat('googAvailableSendBandwidth')) / 1000)
};
try {
if (getStatValue(now, 'receiveBandwidth') ||
getStatValue(now, 'sendBandwidth')) {
PeerStats.bandwidth = {
"download": Math.round(
(getStatValue(now, 'receiveBandwidth')) / 1000),
"upload": Math.round(
(getStatValue(now, 'sendBandwidth')) / 1000)
};
}
}
catch(e){/*not supported*/}
if(now.type == 'googCandidatePair')
{
var ip = now.stat('googRemoteAddress');
var type = now.stat("googTransportType");
var localIP = now.stat("googLocalAddress");
var active = now.stat("googActiveConnection");
var ip, type, localIP, active;
try {
ip = getStatValue(now, 'remoteAddress');
type = getStatValue(now, "transportType");
localIP = getStatValue(now, "localAddress");
active = getStatValue(now, "activeConnection");
}
catch(e){/*not supported*/}
if(!ip || !type || !localIP || active != "true")
continue;
var addressSaved = false;
......@@ -252,17 +322,32 @@ StatsCollector.prototype.processStatsReport = function () {
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;
}
var before = this.baselineStatsReport[idx];
if (!before) {
console.warn(now.stat('ssrc') + ' not enough data');
console.warn(getStatValue(now, 'ssrc') + ' not enough data');
continue;
}
var ssrc = now.stat('ssrc');
var ssrc = getStatValue(now, 'ssrc');
if(!ssrc)
continue;
var jid = ssrc2jid[ssrc];
if (!jid) {
console.warn("No jid for ssrc: " + ssrc);
......@@ -278,31 +363,30 @@ StatsCollector.prototype.processStatsReport = function () {
var isDownloadStream = true;
var key = 'packetsReceived';
if (!now.stat(key))
if (!getStatValue(now, key))
{
isDownloadStream = false;
key = 'packetsSent';
if (!now.stat(key))
if (!getStatValue(now, key))
{
console.error("No packetsReceived nor packetSent stat found");
this.stop();
return;
console.warn("No packetsReceived nor packetSent stat found");
continue;
}
}
var packetsNow = now.stat(key);
var packetsNow = getStatValue(now, key);
if(!packetsNow || packetsNow < 0)
packetsNow = 0;
var packetsBefore = before.stat(key);
var packetsBefore = getStatValue(before, key);
if(!packetsBefore || packetsBefore < 0)
packetsBefore = 0;
var packetRate = packetsNow - packetsBefore;
if(!packetRate || packetRate < 0)
packetRate = 0;
var currentLoss = now.stat('packetsLost');
var currentLoss = getStatValue(now, 'packetsLost');
if(!currentLoss || currentLoss < 0)
currentLoss = 0;
var previousLoss = before.stat('packetsLost');
var previousLoss = getStatValue(before, 'packetsLost');
if(!previousLoss || previousLoss < 0)
previousLoss = 0;
var lossRate = currentLoss - previousLoss;
......@@ -315,16 +399,18 @@ StatsCollector.prototype.processStatsReport = function () {
"packetsLost": lossRate,
"isDownloadStream": isDownloadStream});
var bytesReceived = 0, bytesSent = 0;
if(now.stat("bytesReceived"))
if(getStatValue(now, "bytesReceived"))
{
bytesReceived = now.stat("bytesReceived") -
before.stat("bytesReceived");
bytesReceived = getStatValue(now, "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);
......@@ -349,19 +435,21 @@ StatsCollector.prototype.processStatsReport = function () {
jidStats.setSsrcBitrate(ssrc, {
"download": bytesReceived,
"upload": bytesSent});
var resolution = {height: null, width: null};
if(now.stat("googFrameHeightReceived") &&
now.stat("googFrameWidthReceived"))
{
resolution.height = now.stat("googFrameHeightReceived");
resolution.width = now.stat("googFrameWidthReceived");
}
else if(now.stat("googFrameHeightSent") &&
now.stat("googFrameWidthSent"))
{
resolution.height = now.stat("googFrameHeightSent");
resolution.width = now.stat("googFrameWidthSent");
try {
if (getStatValue(now, "googFrameHeightReceived") &&
getStatValue(now, "googFrameWidthReceived")) {
resolution.height = getStatValue(now, "googFrameHeightReceived");
resolution.width = getStatValue(now, "googFrameWidthReceived");
}
else if (getStatValue(now, "googFrameHeightSent") &&
getStatValue(now, "googFrameWidthSent")) {
resolution.height = getStatValue(now, "googFrameHeightSent");
resolution.width = getStatValue(now, "googFrameWidthSent");
}
}
catch(e){/*not supported*/}
if(resolution.height && resolution.width)
{
......@@ -403,6 +491,8 @@ StatsCollector.prototype.processStatsReport = function () {
self.jid2stats[jid].ssrc2bitrate[ssrc].download;
bitrateUpload +=
self.jid2stats[jid].ssrc2bitrate[ssrc].upload;
delete self.jid2stats[jid].ssrc2bitrate[ssrc];
}
);
resolutions[jid] = self.jid2stats[jid].ssrc2resolution;
......@@ -454,11 +544,11 @@ StatsCollector.prototype.processAudioLevelReport = function ()
var before = this.baselineAudioLevelsReport[idx];
if (!before)
{
console.warn(now.stat('ssrc') + ' not enough data');
console.warn(getStatValue(now, 'ssrc') + ' not enough data');
continue;
}
var ssrc = now.stat('ssrc');
var ssrc = getStatValue(now, 'ssrc');
var jid = ssrc2jid[ssrc];
if (!jid)
{
......@@ -474,9 +564,19 @@ StatsCollector.prototype.processAudioLevelReport = function ()
}
// Audio level
var audioLevel = now.stat('audioInputLevel');
if (!audioLevel)
audioLevel = now.stat('audioOutputLevel');
var audioLevel = null;
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)
{
// TODO: can't find specs about what this value really is,
......@@ -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
......@@ -51,12 +51,10 @@ var Util = (function (my) {
* Returns the available video width.
*/
my.getAvailableVideoWidth = function () {
var chatspaceWidth
= (Chat.isVisible() || ContactList.isVisible())
? $('#chatspace').width()
: 0;
var rightPanelWidth
= PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
return window.innerWidth - chatspaceWidth;
return window.innerWidth - rightPanelWidth;
};
my.imageToGrayScale = function (canvas) {
......
......@@ -9,11 +9,24 @@ var VideoLayout = (function (my) {
updateInProgress: false,
newSrc: ''
};
var defaultLocalDisplayName = "Me";
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;
VideoLayout.changeLocalVideo(stream, true);
}
my.changeLocalAudio = function(stream) {
connection.jingle.localAudio = stream;
RTC.attachMediaStream($('#localAudio'), stream);
document.getElementById('localAudio').autoplay = true;
document.getElementById('localAudio').volume = 0;
......@@ -23,7 +36,7 @@ var VideoLayout = (function (my) {
connection.jingle.localVideo = stream;
var localVideo = document.createElement('video');
localVideo.id = 'localVideo_' + stream.id;
localVideo.id = 'localVideo_' + RTC.getStreamID(stream);
localVideo.autoplay = true;
localVideo.volume = 0; // is it required if audio is separated ?
localVideo.oncontextmenu = function () { return false; };
......@@ -45,10 +58,10 @@ var VideoLayout = (function (my) {
// Add click handler to both video and video wrapper elements in case
// there's no video.
localVideoSelector.click(function () {
VideoLayout.handleVideoThumbClicked(localVideo.src);
VideoLayout.handleVideoThumbClicked(RTC.getVideoSrc(localVideo), false, connection.emuc.myroomjid);
});
$('#localVideoContainer').click(function () {
VideoLayout.handleVideoThumbClicked(localVideo.src);
VideoLayout.handleVideoThumbClicked(RTC.getVideoSrc(localVideo), false, connection.emuc.myroomjid);
});
// Add hover handler
......@@ -58,14 +71,14 @@ var VideoLayout = (function (my) {
},
function() {
if (!VideoLayout.isLargeVideoVisible()
|| localVideo.src !== $('#largeVideo').attr('src'))
|| RTC.getVideoSrc(localVideo) !== RTC.getVideoSrc($('#largeVideo')[0]))
VideoLayout.showDisplayName('localVideoContainer', false);
}
);
// Add stream ended handler
stream.onended = function () {
localVideoContainer.removeChild(localVideo);
VideoLayout.updateRemovedVideo(localVideo.src);
VideoLayout.updateRemovedVideo(RTC.getVideoSrc(localVideo));
};
// Flip video x axis if needed
flipXLocalVideo = flipX;
......@@ -76,9 +89,16 @@ var VideoLayout = (function (my) {
var videoStream = simulcast.getLocalVideoStream();
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) {
* @param removedVideoSrc src stream identifier of the video.
*/
my.updateRemovedVideo = function(removedVideoSrc) {
if (removedVideoSrc === $('#largeVideo').attr('src')) {
if (removedVideoSrc === RTC.getVideoSrc($('#largeVideo')[0])) {
// this is currently displayed as large
// pick the last visible video in the row
// if nobody else is left, this picks the local video
......@@ -99,7 +119,7 @@ var VideoLayout = (function (my) {
console.info("Last visible video no longer exists");
pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
if (!pick || !pick.src) {
if (!pick || !RTC.getVideoSrc(pick)) {
// Try local video
console.info("Fallback to local video...");
pick = $('#remoteVideos>span>span>video').get(0);
......@@ -108,21 +128,40 @@ var VideoLayout = (function (my) {
// mute if localvideo
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 {
console.warn("Failed to elect large video");
}
}
};
my.getLargeVideoState = function () {
return largeVideoState;
}
/**
* 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);
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
// fadeOut event triggers. In that case the getJidFromVideoSrc and
// isVideoSrcDesktop methods will not function correctly.
......@@ -133,15 +172,22 @@ var VideoLayout = (function (my) {
largeVideoState.newSrc = newSrc;
largeVideoState.isVisible = $('#largeVideo').is(':visible');
largeVideoState.isDesktop = isVideoSrcDesktop(newSrc);
largeVideoState.userJid = getJidFromVideoSrc(newSrc);
largeVideoState.isDesktop = isVideoSrcDesktop(jid);
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
largeVideoState.flipX = (newSrc === localVideoSrc) && flipXLocalVideo;
var oldSrc = $('#largeVideo').attr('src');
largeVideoState.oldJid = getJidFromVideoSrc(oldSrc);
var userChanged = false;
if (largeVideoState.oldJid != largeVideoState.userJid) {
userChanged = true;
......@@ -155,9 +201,12 @@ var VideoLayout = (function (my) {
var doUpdate = function () {
Avatar.updateActiveSpeakerAvatarSrc(largeVideoState.userJid);
if (!userChanged && largeVideoState.preload
&& largeVideoState.preload != null
&& $(largeVideoState.preload).attr('src') == newSrc) {
&& RTC.getVideoSrc($(largeVideoState.preload)[0]) == newSrc)
{
console.info('Switching to preloaded video');
var attributes = $('#largeVideo').prop("attributes");
......@@ -183,7 +232,7 @@ var VideoLayout = (function (my) {
largeVideoState.preload = null;
largeVideoState.preload_ssrc = 0;
} else {
$('#largeVideo').attr('src', largeVideoState.newSrc);
RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
}
var videoTransform = document.getElementById('largeVideo')
......@@ -211,14 +260,12 @@ var VideoLayout = (function (my) {
// Only if the large video is currently visible.
// Disable previous dominant speaker video.
if (largeVideoState.oldJid) {
var oldResourceJid = Strophe.getResourceFromJid(largeVideoState.oldJid);
VideoLayout.enableDominantSpeaker(oldResourceJid, false);
VideoLayout.enableDominantSpeaker(largeVideoState.oldJid, false);
}
// Enable new dominant speaker in the remote videos section.
if (largeVideoState.userJid) {
var resourceJid = Strophe.getResourceFromJid(largeVideoState.userJid);
VideoLayout.enableDominantSpeaker(resourceJid, true);
VideoLayout.enableDominantSpeaker(largeVideoState.userJid, true);
}
if (userChanged && largeVideoState.isVisible) {
......@@ -227,6 +274,10 @@ var VideoLayout = (function (my) {
$(this).fadeIn(300);
}
if(userChanged) {
Avatar.showUserAvatar(largeVideoState.oldJid);
}
largeVideoState.updateInProgress = false;
};
......@@ -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
var focusJid = getJidFromVideoSrc(focusedVideoSrc);
var oldContainer = getParticipantContainer(focusJid);
var oldContainer = null;
if(focusedVideoSrc) {
var focusJid = focusedVideoSrc.jid;
oldContainer = getParticipantContainer(focusJid);
}
if (oldContainer) {
oldContainer.removeClass("videoContainerFocused");
}
// Unlock current focused.
if (focusedVideoSrc === videoSrc)
if (focusedVideoSrc && focusedVideoSrc.src === videoSrc)
{
focusedVideoSrc = null;
var dominantSpeakerVideo = null;
......@@ -260,7 +314,7 @@ var VideoLayout = (function (my) {
.get(0);
if (dominantSpeakerVideo) {
VideoLayout.updateLargeVideo(dominantSpeakerVideo.src, 1);
VideoLayout.updateLargeVideo(RTC.getVideoSrc(dominantSpeakerVideo), 1, currentDominantSpeaker);
}
}
......@@ -271,17 +325,19 @@ var VideoLayout = (function (my) {
}
// Lock new video
focusedVideoSrc = videoSrc;
focusedVideoSrc = {
src: videoSrc,
jid: jid
};
// Update focused/pinned interface.
var userJid = getJidFromVideoSrc(videoSrc);
if (userJid)
if (jid)
{
var container = getParticipantContainer(userJid);
var container = getParticipantContainer(jid);
container.addClass("videoContainerFocused");
if (!noPinnedEndpointChangedEvent) {
$(document).trigger("pinnedendpointchanged", [userJid]);
$(document).trigger("pinnedendpointchanged", [jid]);
}
}
......@@ -293,7 +349,7 @@ var VideoLayout = (function (my) {
// this isn't a prezi.
$(document).trigger("video.selected", [false]);
VideoLayout.updateLargeVideo(videoSrc, 1);
VideoLayout.updateLargeVideo(videoSrc, 1, Strophe.getResourceFromJid(jid));
$('audio').each(function (idx, el) {
if (el.id.indexOf('mixedmslabel') !== -1) {
......@@ -339,8 +395,7 @@ var VideoLayout = (function (my) {
* Shows/hides the large video.
*/
my.setLargeVideoVisible = function(isVisible) {
var largeVideoJid = getJidFromVideoSrc($('#largeVideo').attr('src'));
var resourceJid = Strophe.getResourceFromJid(largeVideoJid);
var resourceJid = largeVideoState.userJid;
if (isVisible) {
$('#largeVideo').css({visibility: 'visible'});
......@@ -368,12 +423,13 @@ var VideoLayout = (function (my) {
* in the document and creates it eventually.
*
* @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,
* <tt>false</tt> - otherwise
*/
my.ensurePeerContainerExists = function(peerJid) {
ContactList.ensureAddContact(peerJid);
my.ensurePeerContainerExists = function(peerJid, userId) {
ContactList.ensureAddContact(peerJid, userId);
var resourceJid = Strophe.getResourceFromJid(peerJid);
......@@ -382,14 +438,15 @@ var VideoLayout = (function (my) {
if ($('#' + videoSpanId).length > 0) {
// If there's been a focus change, make sure we add focus related
// interface!!
if (focus && $('#remote_popupmenu_' + resourceJid).length <= 0)
addRemoteVideoMenu( peerJid,
document.getElementById(videoSpanId));
if (focus && $('#remote_popupmenu_' + resourceJid).length <= 0) {
addRemoteVideoMenu(peerJid,
document.getElementById(videoSpanId));
}
}
else {
var container
= VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId);
var container =
VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId, userId);
Avatar.setUserAvatar(peerJid, userId);
// Set default display name.
setDisplayName(videoSpanId);
......@@ -438,7 +495,7 @@ var VideoLayout = (function (my) {
? document.createElement('video')
: document.createElement('audio');
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
+ sid + '_' + stream.id;
+ sid + '_' + RTC.getStreamID(stream);
element.id = id;
element.autoplay = true;
......@@ -469,7 +526,7 @@ var VideoLayout = (function (my) {
RTC.attachMediaStream(sel, videoStream);
if (isVideo)
waitForRemoteVideo(sel, thessrc, stream);
waitForRemoteVideo(sel, thessrc, stream, peerJid);
}
stream.onended = function () {
......@@ -491,7 +548,7 @@ var VideoLayout = (function (my) {
var videoThumb = $('#' + container.id + '>video').get(0);
if (videoThumb)
VideoLayout.handleVideoThumbClicked(videoThumb.src);
VideoLayout.handleVideoThumbClicked(RTC.getVideoSrc(videoThumb), false, peerJid);
event.preventDefault();
return false;
......@@ -506,13 +563,13 @@ var VideoLayout = (function (my) {
var videoSrc = null;
if ($('#' + container.id + '>video')
&& $('#' + 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
// keep the display name on place.
if (!VideoLayout.isLargeVideoVisible()
|| videoSrc !== $('#largeVideo').attr('src'))
|| videoSrc !== RTC.getVideoSrc($('#largeVideo')[0]))
VideoLayout.showDisplayName(container.id, false);
}
);
......@@ -537,13 +594,11 @@ var VideoLayout = (function (my) {
var removedVideoSrc = null;
if (isVideo) {
select = $('#' + container.id + '>video');
removedVideoSrc = select.get(0).src;
removedVideoSrc = RTC.getVideoSrc(select.get(0));
}
else
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
// before has started)
......@@ -586,14 +641,17 @@ var VideoLayout = (function (my) {
peerContainer.show();
}
// TODO(gp) add proper avatars handling.
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')
{
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)
......@@ -619,7 +677,7 @@ var VideoLayout = (function (my) {
*/
function setDisplayName(videoSpanId, 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 (nameSpan.length > 0) {
......@@ -680,6 +738,7 @@ var VideoLayout = (function (my) {
.bind("click", function (e) {
e.preventDefault();
e.stopPropagation();
$('#localDisplayName').hide();
$('#editDisplayName').show();
$('#editDisplayName').focus();
......@@ -698,7 +757,7 @@ var VideoLayout = (function (my) {
});
}
}
};
}
my.inputDisplayNameHandler = function (name) {
if (nickname !== name) {
......@@ -715,7 +774,7 @@ var VideoLayout = (function (my) {
$('#localDisplayName').text(nickname + " (me)");
else
$('#localDisplayName')
.text(defaultLocalDisplayName);
.text(interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
$('#localDisplayName').show();
}
......@@ -911,6 +970,10 @@ var VideoLayout = (function (my) {
$('#largeVideoContainer').width(availableWidth);
$('#largeVideoContainer').height(availableHeight);
$('#activeSpeakerAvatar').css('top',
(availableHeight - interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE) / 2);
VideoLayout.resizeThumbnails();
};
......@@ -930,6 +993,8 @@ var VideoLayout = (function (my) {
$('#remoteVideos>span').width(width);
$('#remoteVideos>span').height(height);
$('.userAvatar').css('left', (width - height) / 2);
$(document).trigger("remotevideo.resized", [width, height]);
};
......@@ -968,7 +1033,6 @@ var VideoLayout = (function (my) {
videoSpan = document.getElementById(videoContainerId);
if (!videoSpan) {
console.error("No video element for jid", resourceJid);
return;
}
......@@ -1184,22 +1248,6 @@ var VideoLayout = (function (my) {
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
* given <tt>parentElement</tt>.
......@@ -1302,7 +1350,7 @@ var VideoLayout = (function (my) {
// We have a video src, great! Let's update the large video
// now.
VideoLayout.handleVideoThumbClicked(videoThumb.src);
VideoLayout.handleVideoThumbClicked(videoThumb.src, false, jid);
} else {
// If we don't have a video src for jid, there's absolutely
......@@ -1430,7 +1478,7 @@ var VideoLayout = (function (my) {
// Update the large video if the video source is already available,
// otherwise wait for the "videoactive.jingle" event.
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) {
// it is no longer being received. If resourceJid was being
// displayed in the large video we have to switch to another
// user.
var largeVideoResource = VideoLayout.getLargeVideoResource();
var largeVideoResource = largeVideoState.userJid;
if (!updateLargeVideo && resourceJid === largeVideoResource) {
updateLargeVideo = true;
}
......@@ -1527,36 +1575,26 @@ var VideoLayout = (function (my) {
if (!isVisible) {
console.log("Add to last N", resourceJid);
mediaStreams.some(function (mediaStream) {
if (mediaStream.peerjid
&& Strophe.getResourceFromJid(mediaStream.peerjid)
=== 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;
}
var jid = connection.emuc.findJidFromResource(resourceJid);
var mediaStream = mediaStreams[jid][MediaStream.VIDEO_TYPE];
var sel = $('#participant_' + resourceJid + '>video');
waitForRemoteVideo(
sel,
mediaStream.ssrc,
mediaStream.stream);
return true;
}
});
var videoStream = simulcast.getReceivingVideoStream(
mediaStream.stream);
RTC.attachMediaStream(sel, videoStream);
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, mediaStream.peerjid);
updateLargeVideo = false;
}
waitForRemoteVideo(sel, mediaStream.ssrc, mediaStream.stream, resourceJid);
}
});
})
}
// The endpoint that was being shown in the large video has dropped out
......@@ -1611,7 +1649,7 @@ var VideoLayout = (function (my) {
|| (parentResourceJid
&& VideoLayout.getDominantSpeakerResourceJid()
=== parentResourceJid)) {
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1);
VideoLayout.updateLargeVideo(RTC.getVideoSrc(videoelem[0]), 1, parentResourceJid);
}
VideoLayout.showFocusIndicator();
......@@ -1622,7 +1660,15 @@ var VideoLayout = (function (my) {
endpointSimulcastLayers.forEach(function (esl) {
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;
}
......@@ -1639,12 +1685,8 @@ var VideoLayout = (function (my) {
console.info([esl, primarySSRC, msid, session, electedStream]);
var msidParts = msid.split(' ');
var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join(''));
// FIXME(gp) here we should use the VideoLayout.getPeerContainerResource
// and VideoLayout.getLargeVideoResource methods.
var preload = (ssrc2jid[videoSrcToSsrc[selRemoteVideo.attr('src')]]
== ssrc2jid[videoSrcToSsrc[largeVideoState.newSrc]]);
var preload = (Strophe.getResourceFromJid(ssrc2jid[primarySSRC]) == largeVideoState.userJid);
if (preload) {
if (largeVideoState.preload)
......@@ -1656,9 +1698,7 @@ var VideoLayout = (function (my) {
// ssrcs are unique in an rtp session
largeVideoState.preload_ssrc = primarySSRC;
var electedStreamUrl = webkitURL.createObjectURL(electedStream);
largeVideoState.preload
.attr('src', electedStreamUrl);
RTC.attachMediaStream(largeVideoState.preload, electedStream)
}
} else {
......@@ -1674,7 +1714,19 @@ var VideoLayout = (function (my) {
endpointSimulcastLayers.forEach(function (esl) {
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;
}
......@@ -1694,21 +1746,15 @@ var VideoLayout = (function (my) {
var msidParts = msid.split(' ');
var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join(''));
// FIXME(gp) here we should use the VideoLayout.getPeerContainerResource
// and VideoLayout.getLargeVideoResource methods.
var updateLargeVideo = (ssrc2jid[videoSrcToSsrc[selRemoteVideo.attr('src')]]
== ssrc2jid[videoSrcToSsrc[largeVideoState.newSrc]]);
// We should only update the focused video src if it's not a
// falsy value.
var updateFocusedVideoSrc
= focusedVideoSrc && focusedVideoSrc !== ''
&& (selRemoteVideo.attr('src') == focusedVideoSrc);
var updateLargeVideo = (Strophe.getResourceFromJid(ssrc2jid[primarySSRC])
== largeVideoState.userJid);
var updateFocusedVideoSrc = (focusedVideoSrc && focusedVideoSrc.src && focusedVideoSrc.src != '' &&
(RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoSrc.src));
var electedStreamUrl;
if (largeVideoState.preload_ssrc == primarySSRC)
{
electedStreamUrl = $(largeVideoState.preload).attr('src');
RTC.setVideoSrc(selRemoteVideo[0], RTC.getVideoSrc(largeVideoState.preload[0]));
}
else
{
......@@ -1719,18 +1765,19 @@ var VideoLayout = (function (my) {
largeVideoState.preload_ssrc = 0;
electedStreamUrl = webkitURL.createObjectURL(electedStream);
RTC.attachMediaStream(selRemoteVideo, electedStream);
}
selRemoteVideo.attr('src', electedStreamUrl);
videoSrcToSsrc[selRemoteVideo.attr('src')] = primarySSRC + ''; // what we store there is typeof string.
var jid = ssrc2jid[primarySSRC];
jid2Ssrc[jid] = primarySSRC;
if (updateLargeVideo) {
VideoLayout.updateLargeVideo(electedStreamUrl);
VideoLayout.updateLargeVideo(RTC.getVideoSrc(selRemoteVideo[0]), null,
Strophe.getResourceFromJid(jid));
}
if (updateFocusedVideoSrc) {
focusedVideoSrc = electedStreamUrl;
focusedVideoSrc.src = RTC.getVideoSrc(selRemoteVideo[0]);
}
var videoId;
......@@ -1854,19 +1901,25 @@ var VideoLayout = (function (my) {
if(this.jid==null)
{
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];
if(resolutionValue)
resolution = "N/A";
}
else
for(var i in this.resolution)
{
if(resolutionValue.height &&
resolutionValue.width)
resolutionValue = this.resolution[i];
if(resolutionValue)
{
resolution += (resolution == ""? "" : ", ")
+ resolutionValue.width + "x" + resolutionValue.height;
if(resolutionValue.height &&
resolutionValue.width)
{
resolution += (resolution == ""? "" : ", ")
+ resolutionValue.width + "x" + resolutionValue.height;
}
}
}
}
}
else if(!resolutionValue ||
!resolutionValue.height ||
......
......@@ -8,6 +8,7 @@
<%@ page import="org.jitsi.videobridge.openfire.*" %>
<%@ page import="org.jivesoftware.openfire.*" %>
<%@ page import="org.jivesoftware.util.*" %>
<%@ page import="java.io.File" %>
<%@ 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/fmt_rt" prefix="fmt" %>
......@@ -119,7 +120,13 @@
JiveGlobals.setProperty("org.jitsi.videobridge.ofmeet.sip.password", clientpassword);
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 @@
<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" />
</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>
</table>
</p>
......@@ -350,7 +374,7 @@
<td align="left" width="150">
<fmt:message key="config.page.configuration.server"/>
</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", "") %>">
</td>
</tr>
......@@ -359,7 +383,7 @@
<td align="left" width="150">
<fmt:message key="config.page.configuration.outboundproxy"/>
</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", "") %>">
</td>
</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