Adds a last-n user interface. Some code restructuring related to last-n and stream reception/deletion. Adds a contact list user interface.
This commit is contained in:
parent
325af308f5
commit
e89c7ea85c
204
app.js
204
app.js
|
@ -11,6 +11,8 @@ var recordingToken ='';
|
|||
var roomUrl = null;
|
||||
var roomName = null;
|
||||
var ssrc2jid = {};
|
||||
var mediaStreams = [];
|
||||
|
||||
/**
|
||||
* The stats collector that process stats data and triggers updates to app.js.
|
||||
* @type {StatsCollector}
|
||||
|
@ -231,40 +233,41 @@ function doJoin() {
|
|||
connection.emuc.doJoin(roomjid);
|
||||
}
|
||||
|
||||
$(document).bind('remotestreamadded.jingle', function (event, data, sid) {
|
||||
function waitForRemoteVideo(selector, sid, ssrc) {
|
||||
if (selector.removed) {
|
||||
console.warn("media removed before had started", selector);
|
||||
return;
|
||||
}
|
||||
var sess = connection.jingle.sessions[sid];
|
||||
if (data.stream.id === 'mixedmslabel') return;
|
||||
var videoTracks = data.stream.getVideoTracks();
|
||||
// console.log("waiting..", videoTracks, selector[0]);
|
||||
|
||||
if (videoTracks.length === 0 || selector[0].currentTime > 0) {
|
||||
RTC.attachMediaStream(selector, data.stream); // FIXME: why do i have to do this for FF?
|
||||
|
||||
// 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) {
|
||||
videoSrcToSsrc[sel.attr('src')] = ssrc;
|
||||
} else {
|
||||
console.warn("No ssrc given for video", sel);
|
||||
}
|
||||
|
||||
$(document).trigger('callactive.jingle', [selector, sid]);
|
||||
console.log('waitForremotevideo', sess.peerconnection.iceConnectionState, sess.peerconnection.signalingState);
|
||||
} else {
|
||||
setTimeout(function () { waitForRemoteVideo(selector, sid, ssrc); }, 250);
|
||||
}
|
||||
function waitForRemoteVideo(selector, ssrc, stream) {
|
||||
if (selector.removed || !selector.parent().is(":visible")) {
|
||||
console.warn("Media removed before had started", selector);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream.id === 'mixedmslabel') return;
|
||||
|
||||
if (selector[0].currentTime > 0) {
|
||||
RTC.attachMediaStream(selector, stream); // FIXME: why do i have to do this for FF?
|
||||
|
||||
// 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;
|
||||
} else {
|
||||
console.warn("No ssrc given for video", selector);
|
||||
}
|
||||
|
||||
$(document).trigger('videoactive.jingle', [selector]);
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
waitForRemoteVideo(selector, ssrc, stream);
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
|
||||
$(document).bind('remotestreamadded.jingle', function (event, 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) {
|
||||
var ssrclines = SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc');
|
||||
var ssrclines
|
||||
= SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc');
|
||||
ssrclines = ssrclines.filter(function (line) {
|
||||
return line.indexOf('mslabel:' + data.stream.label) !== -1;
|
||||
});
|
||||
|
@ -278,11 +281,14 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
|
|||
}
|
||||
}
|
||||
|
||||
mediaStreams.push(new MediaStream(data, sid, thessrc));
|
||||
|
||||
var container;
|
||||
var remotes = document.getElementById('remoteVideos');
|
||||
|
||||
if (data.peerjid) {
|
||||
VideoLayout.ensurePeerContainerExists(data.peerjid);
|
||||
|
||||
container = document.getElementById(
|
||||
'participant_' + Strophe.getResourceFromJid(data.peerjid));
|
||||
} else {
|
||||
|
@ -295,91 +301,22 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
|
|||
}
|
||||
// FIXME: for the mixed ms we dont need a video -- currently
|
||||
container = document.createElement('span');
|
||||
container.id = 'mixedstream';
|
||||
container.className = 'videocontainer';
|
||||
remotes.appendChild(container);
|
||||
Util.playSoundNotification('userJoined');
|
||||
}
|
||||
|
||||
var isVideo = data.stream.getVideoTracks().length > 0;
|
||||
var vid = isVideo ? document.createElement('video') : document.createElement('audio');
|
||||
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') + sid + '_' + data.stream.id;
|
||||
|
||||
vid.id = id;
|
||||
vid.autoplay = true;
|
||||
vid.oncontextmenu = function () { return false; };
|
||||
|
||||
container.appendChild(vid);
|
||||
|
||||
// TODO: make mixedstream display:none via css?
|
||||
if (id.indexOf('mixedmslabel') !== -1) {
|
||||
container.id = 'mixedstream';
|
||||
$(container).hide();
|
||||
if (container) {
|
||||
VideoLayout.addRemoteStreamElement( container,
|
||||
sid,
|
||||
data.stream,
|
||||
data.peerjid,
|
||||
thessrc);
|
||||
}
|
||||
|
||||
var sel = $('#' + id);
|
||||
sel.hide();
|
||||
RTC.attachMediaStream(sel, data.stream);
|
||||
|
||||
if (isVideo) {
|
||||
waitForRemoteVideo(sel, sid, thessrc);
|
||||
}
|
||||
|
||||
data.stream.onended = function () {
|
||||
console.log('stream ended', this.id);
|
||||
|
||||
// Mark video as removed to cancel waiting loop(if video is removed
|
||||
// before has started)
|
||||
sel.removed = true;
|
||||
sel.remove();
|
||||
|
||||
var audioCount = $('#' + container.id + '>audio').length;
|
||||
var videoCount = $('#' + container.id + '>video').length;
|
||||
if (!audioCount && !videoCount) {
|
||||
console.log("Remove whole user", container.id);
|
||||
// Remove whole container
|
||||
container.remove();
|
||||
Util.playSoundNotification('userLeft');
|
||||
VideoLayout.resizeThumbnails();
|
||||
}
|
||||
|
||||
VideoLayout.checkChangeLargeVideo(vid.src);
|
||||
};
|
||||
|
||||
// Add click handler.
|
||||
container.onclick = function (event) {
|
||||
/*
|
||||
* FIXME It turns out that videoThumb may not exist (if there is no
|
||||
* actual video).
|
||||
*/
|
||||
var videoThumb = $('#' + container.id + '>video').get(0);
|
||||
|
||||
if (videoThumb)
|
||||
VideoLayout.handleVideoThumbClicked(videoThumb.src);
|
||||
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Add hover handler
|
||||
$(container).hover(
|
||||
function() {
|
||||
VideoLayout.showDisplayName(container.id, true);
|
||||
},
|
||||
function() {
|
||||
var videoSrc = null;
|
||||
if ($('#' + container.id + '>video')
|
||||
&& $('#' + container.id + '>video').length > 0) {
|
||||
videoSrc = $('#' + container.id + '>video').get(0).src;
|
||||
}
|
||||
|
||||
// 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'))
|
||||
VideoLayout.showDisplayName(container.id, false);
|
||||
}
|
||||
);
|
||||
|
||||
// an attempt to work around https://github.com/jitsi/jitmeet/issues/32
|
||||
if (isVideo &&
|
||||
data.peerjid && sess.peerjid === data.peerjid &&
|
||||
|
@ -587,21 +524,6 @@ $(document).bind('conferenceCreated.jingle', function (event, focus)
|
|||
}
|
||||
});
|
||||
|
||||
$(document).bind('callactive.jingle', function (event, videoelem, sid) {
|
||||
if (videoelem.attr('id').indexOf('mixedmslabel') === -1) {
|
||||
// ignore mixedmslabela0 and v0
|
||||
videoelem.show();
|
||||
VideoLayout.resizeThumbnails();
|
||||
|
||||
// Update the large video to the last added video only if there's no
|
||||
// current active or focused speaker.
|
||||
if (!focusedVideoSrc && !VideoLayout.getDominantSpeakerResourceJid())
|
||||
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1);
|
||||
|
||||
VideoLayout.showFocusIndicator();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).bind('callterminated.jingle', function (event, sid, jid, reason) {
|
||||
// Leave the room if my call has been remotely terminated.
|
||||
if (connection.emuc.joined && focus == null && reason === 'kick') {
|
||||
|
@ -680,14 +602,20 @@ $(document).bind('joined.muc', function (event, jid, info) {
|
|||
|
||||
VideoLayout.showFocusIndicator();
|
||||
|
||||
// Add myself to the contact list.
|
||||
ContactList.addContact(jid);
|
||||
|
||||
// Once we've joined the muc show the toolbar
|
||||
Toolbar.showToolbar();
|
||||
|
||||
var displayName = '';
|
||||
if (info.displayName)
|
||||
displayName = info.displayName + ' (me)';
|
||||
else
|
||||
displayName = "Me";
|
||||
|
||||
VideoLayout.setDisplayName('localVideoContainer', displayName);
|
||||
$(document).trigger('displaynamechanged',
|
||||
['localVideoContainer', displayName]);
|
||||
});
|
||||
|
||||
$(document).bind('entered.muc', function (event, jid, info, pres) {
|
||||
|
@ -811,21 +739,15 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
|
|||
case 'recvonly':
|
||||
el.hide();
|
||||
// FIXME: Check if we have to change large video
|
||||
//VideoLayout.checkChangeLargeVideo(el);
|
||||
//VideoLayout.updateLargeVideo(el);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (jid === connection.emuc.myroomjid) {
|
||||
VideoLayout.setDisplayName('localVideoContainer',
|
||||
info.displayName);
|
||||
} else {
|
||||
VideoLayout.ensurePeerContainerExists(jid);
|
||||
VideoLayout.setDisplayName(
|
||||
'participant_' + Strophe.getResourceFromJid(jid),
|
||||
info.displayName);
|
||||
}
|
||||
if (info.displayName && info.displayName.length > 0)
|
||||
$(document).trigger('displaynamechanged',
|
||||
[jid, info.displayName]);
|
||||
|
||||
if (focus !== null && info.displayName !== null) {
|
||||
focus.setEndpointDisplayName(jid, info.displayName);
|
||||
|
@ -1370,7 +1292,27 @@ function setView(viewName) {
|
|||
// }
|
||||
}
|
||||
|
||||
|
||||
function hangUp() {
|
||||
if (connection && connection.connected) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
$(document).bind('fatalError.jingle',
|
||||
function (event, session, error)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
var BottomToolbar = (function (my) {
|
||||
my.toggleChat = function() {
|
||||
if (ContactList.isVisible()) {
|
||||
buttonClick("#contactListButton", "active");
|
||||
ContactList.toggleContactList();
|
||||
}
|
||||
|
||||
buttonClick("#chatBottomButton", "active");
|
||||
|
||||
Chat.toggleChat();
|
||||
};
|
||||
|
||||
my.toggleContactList = function() {
|
||||
if (Chat.isVisible()) {
|
||||
buttonClick("#chatBottomButton", "active");
|
||||
Chat.toggleChat();
|
||||
}
|
||||
|
||||
buttonClick("#contactListButton", "active");
|
||||
|
||||
ContactList.toggleContactList();
|
||||
};
|
||||
|
||||
|
||||
$(document).bind("remotevideo.resized", function (event, width, height) {
|
||||
var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18;
|
||||
|
||||
$('#bottomToolbar').css({bottom: bottom + 'px'});
|
||||
});
|
||||
|
||||
return my;
|
||||
}(BottomToolbar || {}));
|
9
chat.js
9
chat.js
|
@ -80,7 +80,7 @@ var Chat = (function (my) {
|
|||
else {
|
||||
divClassName = "remoteuser";
|
||||
|
||||
if (!$('#chatspace').is(":visible")) {
|
||||
if (!Chat.isVisible()) {
|
||||
unreadMessages++;
|
||||
Util.playSoundNotification('chatNotification');
|
||||
setVisualNotification(true);
|
||||
|
@ -301,6 +301,13 @@ var Chat = (function (my) {
|
|||
return [chatWidth, availableHeight];
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates if the chat is currently visible.
|
||||
*/
|
||||
my.isVisible = function () {
|
||||
return $('#chatspace').is(":visible");
|
||||
};
|
||||
|
||||
/**
|
||||
* Resizes the chat conversation.
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,7 @@ var config = {
|
|||
minChromeExtVersion: '0.1', // Required version of Chrome extension
|
||||
enableRtpStats: true, // Enables RTP stats processing
|
||||
openSctp: true, // Toggle to enable/disable SCTP channels
|
||||
// channelLastN: -1, // The default value of the channel attribute last-n.
|
||||
channelLastN: -1, // The default value of the channel attribute last-n.
|
||||
// useRtcpMux: true,
|
||||
// useBundle: true,
|
||||
enableRecording: false,
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/**
|
||||
* Contact list.
|
||||
*/
|
||||
var ContactList = (function (my) {
|
||||
/**
|
||||
* Indicates if the chat is currently visible.
|
||||
*
|
||||
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
|
||||
* otherwise
|
||||
*/
|
||||
my.isVisible = function () {
|
||||
return $('#contactlist').is(":visible");
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a contact for the given peerJid if such doesn't yet exist.
|
||||
*
|
||||
* @param peerJid the peerJid corresponding to the contact
|
||||
*/
|
||||
my.ensureAddContact = function(peerJid) {
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
|
||||
|
||||
if (!contact || contact.length <= 0)
|
||||
ContactList.addContact(peerJid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a contact for the given peer jid.
|
||||
*
|
||||
* @param peerJid the jid of the contact to add
|
||||
*/
|
||||
my.addContact = function(peerJid) {
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var contactlist = $('#contactlist>ul');
|
||||
|
||||
var newContact = document.createElement('li');
|
||||
newContact.id = resourceJid;
|
||||
|
||||
newContact.appendChild(createAvatar());
|
||||
newContact.appendChild(createDisplayNameParagraph("Participant"));
|
||||
|
||||
var clElement = contactlist.get(0);
|
||||
|
||||
if (resourceJid === Strophe.getResourceFromJid(connection.emuc.myroomjid)
|
||||
&& $('#contactlist>ul .title')[0].nextSibling.nextSibling)
|
||||
{
|
||||
clElement.insertBefore(newContact,
|
||||
$('#contactlist>ul .title')[0].nextSibling.nextSibling);
|
||||
}
|
||||
else {
|
||||
clElement.appendChild(newContact);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a contact for the given peer jid.
|
||||
*
|
||||
* @param peerJid the peerJid corresponding to the contact to remove
|
||||
*/
|
||||
my.removeContact = function(peerJid) {
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
|
||||
|
||||
if (contact && contact.length > 0) {
|
||||
var contactlist = $('#contactlist>ul');
|
||||
|
||||
contactlist.get(0).removeChild(contact.get(0));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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];
|
||||
|
||||
if (ContactList.isVisible()) {
|
||||
videospace.animate({right: chatSize[0],
|
||||
width: videospaceWidth,
|
||||
height: videospaceHeight},
|
||||
{queue: false,
|
||||
duration: 500});
|
||||
|
||||
$('#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
|
||||
});
|
||||
|
||||
$('#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())
|
||||
Toolbar.dockToolbar(false);
|
||||
|
||||
videospace.animate({right: chatSize[0],
|
||||
width: videospaceWidth,
|
||||
height: videospaceHeight},
|
||||
{queue: false,
|
||||
duration: 500,
|
||||
complete: function () {
|
||||
contactlist.trigger('shown');
|
||||
}
|
||||
});
|
||||
|
||||
$('#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
|
||||
});
|
||||
|
||||
$('#contactlist').show("slide", { direction: "right",
|
||||
queue: false,
|
||||
duration: 500});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the avatar element.
|
||||
*
|
||||
* @return the newly created avatar element
|
||||
*/
|
||||
function createAvatar() {
|
||||
var avatar = document.createElement('i');
|
||||
avatar.className = "icon-avatar avatar";
|
||||
|
||||
return avatar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the display name paragraph.
|
||||
*
|
||||
* @param displayName the display name to set
|
||||
*/
|
||||
function createDisplayNameParagraph(displayName) {
|
||||
var p = document.createElement('p');
|
||||
p.innerHTML = displayName;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates that the display name has changed.
|
||||
*/
|
||||
$(document).bind( 'displaynamechanged',
|
||||
function (event, peerJid, displayName) {
|
||||
if (peerJid === 'localVideoContainer')
|
||||
peerJid = connection.emuc.myroomjid;
|
||||
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var contactName = $('#contactlist #' + resourceJid + '>p');
|
||||
|
||||
if (contactName && displayName && displayName.length > 0)
|
||||
contactName.html(displayName);
|
||||
});
|
||||
|
||||
return my;
|
||||
}(ContactList || {}));
|
|
@ -0,0 +1,35 @@
|
|||
#contactlist {
|
||||
background-color:rgba(0,0,0,.65);
|
||||
}
|
||||
|
||||
#contactlist>ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#contactlist>ul>li {
|
||||
list-style-type: none;
|
||||
text-align: left;
|
||||
color: #FFF;
|
||||
font-size: 10pt;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
#contactlist>ul>li>p {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#contactlist>ul>li.title {
|
||||
color: #00ccff;
|
||||
font-size: 11pt;
|
||||
border-bottom: 1px solid #676767;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
padding: 0px;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
font-size: 22pt;
|
||||
}
|
|
@ -23,6 +23,12 @@
|
|||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.icon-contactList:before {
|
||||
content: "\e615";
|
||||
}
|
||||
.icon-avatar:before {
|
||||
content: "\e616";
|
||||
}
|
||||
.icon-callRetro:before {
|
||||
content: "\e611";
|
||||
}
|
||||
|
|
56
css/main.css
56
css/main.css
|
@ -8,7 +8,8 @@ html, body{
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#chatspace {
|
||||
#chatspace,
|
||||
#contactlist {
|
||||
display:none;
|
||||
position:absolute;
|
||||
float: right;
|
||||
|
@ -18,12 +19,14 @@ html, body{
|
|||
width: 20%;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
/* background-color:#dfebf1;*/
|
||||
background-color:#FFFFFF;
|
||||
border-left:1px solid #424242;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#chatspace {
|
||||
background-color:#FFF;
|
||||
border-left:1px solid #424242;
|
||||
}
|
||||
|
||||
#chatconversation {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
|
@ -172,7 +175,8 @@ html, body{
|
|||
0 -1px 10px #00ccff;
|
||||
}
|
||||
|
||||
a.button:hover {
|
||||
a.button:hover,
|
||||
a.bottomToolbarButton:hover {
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
|
@ -408,4 +412,46 @@ form {
|
|||
font-weight: 200;
|
||||
}
|
||||
|
||||
#bottomToolbar {
|
||||
display:block;
|
||||
position: absolute;
|
||||
right: -1;
|
||||
bottom: 40px;
|
||||
width: 29px;
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
color: #FFF;
|
||||
border: 1px solid #000;
|
||||
background: rgba(50,50,50,.65);
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
z-index: 6; /*+1 from #remoteVideos*/
|
||||
}
|
||||
|
||||
.bottomToolbarButton {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
color: #FFFFFF;
|
||||
top: 0;
|
||||
padding-top: 3px;
|
||||
width: 29px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
font-size: 10pt;
|
||||
text-align: center;
|
||||
text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #00ccff;
|
||||
}
|
||||
|
||||
.bottomToolbar_span>span {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
font-size: 7pt;
|
||||
color: #ffffff;
|
||||
text-align:center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
padding: 18px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
right: 20px;
|
||||
width:auto;
|
||||
border:1px solid transparent;
|
||||
z-index: 5;
|
||||
|
@ -334,3 +334,7 @@
|
|||
z-index: 0;
|
||||
border-radius:10px;
|
||||
}
|
||||
|
||||
#mixedstream {
|
||||
display:none !important;
|
||||
}
|
||||
|
|
|
@ -74,9 +74,15 @@ function onDataChannel(event)
|
|||
*/
|
||||
var endpointsEnteringLastN = obj.endpointsEnteringLastN;
|
||||
|
||||
console.debug(
|
||||
var stream = obj.stream;
|
||||
|
||||
console.log(
|
||||
"Data channel new last-n event: ",
|
||||
lastNEndpoints);
|
||||
lastNEndpoints, endpointsEnteringLastN, obj);
|
||||
|
||||
$(document).trigger(
|
||||
'lastnchanged',
|
||||
[lastNEndpoints, endpointsEnteringLastN, stream]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
BIN
fonts/jitsi.eot
BIN
fonts/jitsi.eot
Binary file not shown.
|
@ -28,4 +28,6 @@
|
|||
<glyph unicode="" d="M155.131 15.215c0-26.065-21.103-47.215-47.2-47.215h-60.703c-26.098 0-47.229 21.15-47.229 47.215v417.835c0 26.079 21.133 47.229 47.229 47.229h60.701c26.097 0 47.2-21.15 47.2-47.229v-417.835zM538.559 480.28h-280.993c-36.459 0-66.165-30.337-66.165-67.626v-377.058c0-37.259 29.706-67.596 66.165-67.596h280.993c36.49 0 66.197 30.337 66.197 67.596v377.058c0 37.29-29.707 67.626-66.197 67.626zM264.915 413.453h266.327l0.031-71.649h-266.358v71.649zM321.627 25.814h-56.776v56.776h56.776v-56.776zM321.627 128.374h-56.776v56.777h56.776v-56.777zM321.691 231.878h-56.776v56.777h56.776v-56.777zM426.45 25.814h-56.776v56.776h56.776v-56.776zM426.45 128.374h-56.776v56.777h56.776v-56.777zM426.514 231.878h-56.778v56.777h56.778v-56.777zM531.274 25.814h-56.778v56.776h56.778v-56.776zM531.274 128.374h-56.778v56.777h56.778v-56.777zM531.335 231.878h-56.777v56.777h56.777v-56.777z" horiz-adv-x="605" />
|
||||
<glyph unicode="" d="M561.722 469.507c-11.797 13.24-32.066 14.495-45.37 2.697l-504.135-446.718c-13.305-11.734-14.495-32.065-2.73-45.338 6.337-7.153 15.154-10.825 24.063-10.825 7.562 0 15.186 2.7 21.272 8.098l65.023 57.61c45.371-40.922 105.284-66.082 171.237-66.050 141.408 0.031 255.457 113.985 255.644 255.486 0.063 54.967-17.341 105.683-46.75 147.36l59.044 52.313c13.241 11.763 14.499 32.065 2.702 45.368zM472.211 224.909c0.064-100.461-80.948-181.601-181.255-181.476-43.78 0.062-83.786 15.575-115.031 41.284l165.638 146.755v-36.588c0.536-30.497 16.348-46.090 47.472-46.846 30.998 0.756 46.843 16.382 47.565 46.878v20.548h-36.113v-23.75c0.125-2.321-0.282-5.303-1.255-8.974-0.625-1.63-1.724-3.010-3.262-4.046-1.599-1.286-3.923-1.914-6.934-1.914-5.272 0.155-8.566 2.134-9.913 5.961-0.534 1.756-0.974 3.452-1.254 5.082-0.127 1.443-0.188 2.766-0.188 3.893v71.755l21.238 18.817c0.108-0.216 0.226-0.425 0.315-0.651 0.974-3.233 1.381-6.399 1.255-9.538v-18.386h36.113v15.060c-0.123 15.623-4.543 27.35-13.181 35.224l20.356 18.034c17.894-28.028 28.401-61.293 28.433-97.122zM119.897 165.735c-6.306 18.512-9.913 38.279-9.913 58.957-0.095 100.118 80.792 181.005 180.973 181.067 28.426 0 55.156-6.651 79.067-18.199l58.923 52.211c-39.722 25.476-86.879 40.409-137.646 40.474-141.689 0.091-255.677-113.865-255.894-255.838-0.063-39.783 9.318-77.34 25.569-110.941l58.924 52.269zM194.288 313.010h-48.757v-124.529l36.115 32.035v0.344h0.407l58.86 52.209c0 0.282 0.061 0.47 0.061 0.755 0.376 26.949-15.184 40.034-46.687 39.185zM202.98 280.759c0.971-1.384 1.537-3.235 1.661-5.556 0.156-2.226 0.219-4.8 0.219-7.623 0.125-5.458-0.345-9.915-1.475-13.493-1.476-3.797-5.492-5.678-12.079-5.678h-9.662v37.022h7.655c3.921 0 6.933-0.341 9.036-1.095 2.198-0.787 3.734-1.976 4.645-3.577z" horiz-adv-x="570" />
|
||||
<glyph unicode="" d="M290.639 480.854c142.428-0.095 257.404-115.258 257.213-257.498-0.189-142.524-115.036-257.277-257.435-257.308-142.27-0.031-257.656 115.259-257.466 257.211 0.219 142.968 115.005 257.719 257.688 257.595zM290.289 405.878c-100.882-0.061-182.333-81.516-182.239-182.332 0-101.009 81.262-182.368 182.239-182.492 101.009-0.158 182.587 81.515 182.524 182.712-0.126 100.884-81.578 182.175-182.524 182.112zM143.849 312.453h49.098c31.721 0.884 47.392-12.259 47.013-39.431 0.127-9.541-1.106-17.441-3.728-23.761-3.002-6.254-9.353-10.994-19.083-14.090v-0.41c14.186-3.13 21.516-11.787 21.99-25.973v-28.844c0-5.623 0.127-11.406 0.379-17.378 0.41-6.002 1.517-10.49 3.348-13.522h-35.923c-1.863 3.032-3.064 7.519-3.57 13.522-0.506 5.971-0.727 11.755-0.569 17.378v26.161c0 4.801-1.107 8.276-3.286 10.49-2.338 2.053-6.351 3.095-12.006 3.095h-7.299v-70.645h-36.365v163.41zM180.214 247.43h9.732c6.636 0 10.679 1.897 12.166 5.688 1.138 3.602 1.611 8.152 1.484 13.585 0 2.908-0.063 5.434-0.221 7.709-0.126 2.337-0.696 4.202-1.676 5.623-0.916 1.579-2.463 2.781-4.676 3.57-2.117 0.727-5.149 1.106-9.1 1.106h-7.709v-37.282zM249.186 312.453h81.041v-31.343h-44.675v-32.794h39.051v-31.343h-39.051v-36.555h46.411v-31.375h-82.779v163.409zM341.253 268c0.158 15.891 4.708 27.771 13.712 35.703 8.72 7.645 20.093 11.468 34.091 11.468 14.123 0 25.56-3.823 34.312-11.5 8.91-7.899 13.46-19.811 13.586-35.704v-15.166h-36.365v18.516c0.127 3.096-0.285 6.319-1.264 9.604-0.632 1.579-1.738 2.969-3.286 4.107-1.611 0.757-3.949 1.202-6.982 1.202-5.308-0.158-8.625-1.928-9.983-5.309-1.106-3.286-1.611-6.508-1.454-9.604v-80.978c0-1.137 0.063-2.433 0.19-3.886 0.284-1.705 0.727-3.412 1.264-5.116 1.358-3.887 4.676-5.878 9.983-6.003 3.034 0 5.372 0.63 6.982 1.896 1.549 1.075 2.654 2.433 3.286 4.108 0.98 3.665 1.391 6.665 1.264 9.003v23.918h36.365v-20.664c-0.726-30.774-16.682-46.507-47.897-47.235-31.342 0.727-47.265 16.461-47.803 47.171v74.469z" horiz-adv-x="571" />
|
||||
<glyph unicode="" d="M508.412 2.883c-1.026 7.687-2.666 15.269-3.93 22.923-4.167 25.229-16.503 43.252-41.031 53.961-39.187 17.099-77.551 36.060-116.055 54.697-27.843 13.512-26.204 44.26-17.048 57.207 5.945 8.44 11.172 17.286 11.788 28.426 0.222 4.113 4.151 9.495 7.909 11.647 13.035 7.518 19.081 19.782 25.010 32.491 1.555 3.348 3.69 6.594 6.133 9.361 4.236 4.834 6.132 9.618 3.039 15.921-0.717 1.485 0.666 4.167 1.4 6.183 2.152 6.013 5.142 11.838 6.56 18.022 1.778 7.669 2.699 15.612 3.126 23.487 0.187 3.262-3.022 6.764-2.681 9.975 1.741 15.956-7.279 28.101-12.37 41.988-6.233 17.099-18.464 27.81-29.26 40.553-2.033 2.392-2.613 6.526-2.786 9.943-0.36 7.294-3.366 10.898-11.002 9.906-3.055-0.394-6.386-1.248-9.205-0.496-2.478 0.667-6.203 3.144-6.338 5.056-0.769 9.668-4.132 11.258-14.008 9.618-6.182-1.025-14.228 4.577-20.292 8.78-5.072 3.521-9.445 5.023-15.341 3.588-2.457-0.598-5.772-0.495-7.858 0.717-2.221 1.332-4.387 2.119-6.559 2.562v0.374c-0.478-0.016-0.991-0.102-1.469-0.154-0.477 0.051-0.956 0.137-1.434 0.154v-0.375c-2.185-0.444-4.375-1.231-6.578-2.562-2.066-1.213-5.381-1.316-7.84-0.718-5.911 1.434-10.285-0.068-15.342-3.588-6.079-4.202-14.108-9.805-20.292-8.781-9.873 1.641-13.255 0.052-14.024-9.618-0.154-1.912-3.843-4.389-6.338-5.056-2.834-0.752-6.149 0.102-9.223 0.495-7.618 0.992-10.625-2.613-10.985-9.906-0.169-3.416-0.751-7.551-2.784-9.943-10.794-12.743-23.025-23.454-29.278-40.553-5.058-13.886-14.094-26.031-12.335-41.987 0.343-3.211-2.872-6.714-2.7-9.975 0.445-7.875 1.368-15.818 3.127-23.487 1.418-6.184 4.407-12.010 6.576-18.022 0.719-2.016 2.121-4.698 1.384-6.183-3.091-6.303-1.179-11.087 3.058-15.921 2.427-2.767 4.56-6.013 6.115-9.361 5.929-12.709 11.974-24.974 25.007-32.491 3.76-2.152 7.689-7.534 7.929-11.647 0.596-11.14 5.825-19.986 11.785-28.426 9.141-12.947 10.573-43.369-17.081-57.207-38.228-19.132-76.871-37.6-116.021-54.697-24.564-10.709-36.863-28.731-41.032-53.961-1.263-7.656-2.939-15.238-3.929-22.923-1.505-11.464-3.912-34.883-3.912-34.883h512.306c-0.001 0-2.39 23.419-3.894 34.883z" horiz-adv-x="513" />
|
||||
<glyph unicode="" d="M513.087 224.534c0-141.673-114.855-256.526-256.554-256.526-141.674 0-256.534 114.851-256.534 256.526 0 141.692 114.861 256.553 256.534 256.553 141.7 0 256.554-114.861 256.554-256.553zM256.534-31.993c67.863 0 129.556 26.356 175.437 69.37-4.858 5.825-11.276 10.557-19.557 14.171-29.467 12.873-58.313 27.128-87.267 41.128-20.935 10.161-19.702 33.293-12.82 43.029 4.471 6.346 8.402 12.999 8.864 21.373 0.166 3.084 3.12 7.142 5.945 8.761 9.802 5.652 14.349 14.873 18.802 24.43 1.17 2.515 2.777 4.945 4.615 7.038 3.185 3.622 4.612 7.218 2.286 11.971-0.543 1.104 0.502 3.12 1.053 4.637 1.619 4.534 3.866 8.901 4.93 13.558 1.335 5.774 2.029 11.74 2.351 17.661 0.14 2.451-2.272 5.092-2.017 7.493 1.31 12.011-5.471 21.136-9.299 31.579-4.688 12.857-13.885 20.91-22.002 30.485-1.529 1.812-1.964 4.919-2.094 7.476-0.269 5.49-2.53 8.207-8.272 7.462-2.299-0.3-4.805-0.943-6.921-0.378-1.864 0.494-4.663 2.362-4.767 3.802-0.577 7.269-3.106 8.465-10.533 7.238-4.648-0.772-10.697 3.429-15.257 6.601-3.816 2.646-7.104 3.777-11.534 2.69-1.849-0.45-4.341-0.373-5.908 0.547-1.671 0.988-3.303 1.592-4.933 1.919v0.276c-0.36-0.007-0.745-0.065-1.104-0.108-0.361 0.044-0.72 0.103-1.078 0.108v-0.276c-1.645-0.327-3.287-0.931-4.945-1.919-1.556-0.918-4.046-0.996-5.899-0.547-4.443 1.087-7.724-0.044-11.532-2.69-4.578-3.173-10.611-7.373-15.259-6.601-7.431 1.226-9.97 0.031-10.547-7.238-0.109-1.439-2.897-3.308-4.758-3.802-2.139-0.565-4.624 0.077-6.944 0.378-5.728 0.745-7.994-1.971-8.258-7.462-0.131-2.555-0.565-5.665-2.095-7.476-8.111-9.575-17.308-17.629-22.009-30.485-3.814-10.443-10.602-19.568-9.285-31.579 0.256-2.401-2.152-5.042-2.023-7.493 0.327-5.923 1.020-11.888 2.351-17.661 1.065-4.656 3.313-9.024 4.945-13.558 0.547-1.516 1.587-3.531 1.041-4.637-2.325-4.754-0.894-8.351 2.291-11.971 1.837-2.094 3.437-4.523 4.612-7.038 4.45-9.555 8.996-18.779 18.798-24.43 2.827-1.619 5.78-5.676 5.952-8.761 0.457-8.374 4.387-15.027 8.869-21.373 6.873-9.735 7.951-32.623-12.837-43.029-28.76-14.386-57.8-28.255-87.251-41.128-8.285-3.615-14.704-8.347-19.561-14.169 45.88-43.015 107.569-69.372 175.422-69.372z" horiz-adv-x="513" />
|
||||
</font></defs></svg>
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 24 KiB |
BIN
fonts/jitsi.ttf
BIN
fonts/jitsi.ttf
Binary file not shown.
BIN
fonts/jitsi.woff
BIN
fonts/jitsi.woff
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
48
index.html
48
index.html
|
@ -23,15 +23,16 @@
|
|||
<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="config.js?v=3"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
|
||||
<script src="muc.js?v=12"></script><!-- simple MUC library -->
|
||||
<script src="config.js?v=4"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
|
||||
<script src="muc.js?v=13"></script><!-- simple MUC library -->
|
||||
<script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
|
||||
<script src="desktopsharing.js?v=2"></script><!-- desktop sharing -->
|
||||
<script src="data_channels.js?v=2"></script><!-- data channels -->
|
||||
<script src="app.js?v=4"></script><!-- application logic -->
|
||||
<script src="data_channels.js?v=3"></script><!-- data channels -->
|
||||
<script src="app.js?v=5"></script><!-- application logic -->
|
||||
<script src="commands.js?v=1"></script><!-- application logic -->
|
||||
<script src="chat.js?v=8"></script><!-- chat logic -->
|
||||
<script src="util.js?v=5"></script><!-- utility functions -->
|
||||
<script src="chat.js?v=9"></script><!-- chat logic -->
|
||||
<script src="contact_list.js?v=1"></script><!-- contact list logic -->
|
||||
<script src="util.js?v=6"></script><!-- utility functions -->
|
||||
<script src="etherpad.js?v=8"></script><!-- etherpad plugin -->
|
||||
<script src="prezi.js?v=4"></script><!-- prezi plugin -->
|
||||
<script src="smileys.js?v=2"></script><!-- smiley images -->
|
||||
|
@ -40,18 +41,21 @@
|
|||
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
||||
<script src="rtp_stats.js?v=1"></script><!-- RTP stats processing -->
|
||||
<script src="local_stats.js?v=1"></script><!-- Local stats processing -->
|
||||
<script src="videolayout.js?v=7"></script><!-- video ui -->
|
||||
<script src="toolbar.js?v=3"></script><!-- toolbar ui -->
|
||||
<script src="videolayout.js?v=8"></script><!-- video ui -->
|
||||
<script src="toolbar.js?v=4"></script><!-- toolbar ui -->
|
||||
<script src="canvas_util.js?v=1"></script><!-- canvas drawing utils -->
|
||||
<script src="audio_levels.js?v=1"></script><!-- audio levels plugin -->
|
||||
<script src="media_stream.js?v=1"></script><!-- media stream -->
|
||||
<script src="bottom_toolbar.js?v=1"></script><!-- media stream -->
|
||||
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/font.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=22"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=8" id="videolayout_default"/>
|
||||
<link rel="stylesheet" href="css/font.css?v=2"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=23"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=9" id="videolayout_default"/>
|
||||
<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=2">
|
||||
<link rel="stylesheet" href="css/popover.css?v=1">
|
||||
<link rel="stylesheet" href="css/contact_list.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 -->
|
||||
|
@ -158,7 +162,7 @@
|
|||
</a>
|
||||
<div class="header_button_separator"></div>
|
||||
<span class="toolbar_span">
|
||||
<a class="button" data-toggle="popover" data-placement="bottom" data-content="Open / close chat" onclick='Chat.toggleChat();'>
|
||||
<a class="button" data-toggle="popover" data-placement="bottom" data-content="Open / close chat" onclick='BottomToolbar.toggleChat();'>
|
||||
<i id="chatButton" class="icon-chat"></i>
|
||||
</a>
|
||||
<span id="unreadMessages"></span>
|
||||
|
@ -222,6 +226,20 @@
|
|||
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
|
||||
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
|
||||
</div>
|
||||
<span id="bottomToolbar">
|
||||
<span class="bottomToolbar_span">
|
||||
<a class="bottomToolbarButton" data-toggle="popover" data-placement="top" data-content="Open / close chat" onclick='BottomToolbar.toggleChat();'>
|
||||
<i id="chatBottomButton" class="icon-chat-simple"></i>
|
||||
</a>
|
||||
<span id="unreadMessages"></span>
|
||||
</span>
|
||||
<span class="bottomToolbar_span">
|
||||
<a class="bottomToolbarButton" data-toggle="popover" data-placement="top" data-content="Open / close contact list" onclick='BottomToolbar.toggleContactList();'>
|
||||
<i id="contactListButton" class="icon-contactList"></i>
|
||||
</a>
|
||||
<span id="unreadMessages"></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div id="chatspace">
|
||||
<div id="nickname">
|
||||
|
@ -238,5 +256,11 @@
|
|||
</div>
|
||||
<a id="downloadlog" onclick='dump(event.target);' data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
|
||||
</div>
|
||||
<div id="contactlist">
|
||||
<ul>
|
||||
<li class="title"><i class="icon-contact-list"></i> CONTACT LIST</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a id="downloadlog" onclick='dump(event.target);' data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Provides a wrapper class for the MediaStream.
|
||||
*
|
||||
* TODO : Add here the src from the video element and other related properties
|
||||
* and get rid of some of the mappings that we use throughout the UI.
|
||||
*/
|
||||
var MediaStream = (function() {
|
||||
/**
|
||||
* Creates a MediaStream object for the given data, session id and ssrc.
|
||||
*
|
||||
* @param data the data object from which we obtain the stream,
|
||||
* the peerjid, etc.
|
||||
* @param sid the session id
|
||||
* @param ssrc the ssrc corresponding to this MediaStream
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function 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;
|
||||
}
|
||||
|
||||
return MediaStreamProto;
|
||||
})();
|
8
muc.js
8
muc.js
|
@ -373,5 +373,13 @@ Strophe.addConnectionPlugin('emuc', {
|
|||
addVideoInfoToPresence: function(isMuted) {
|
||||
this.presMap['videons'] = 'http://jitsi.org/jitmeet/video';
|
||||
this.presMap['videomuted'] = isMuted.toString();
|
||||
},
|
||||
findJidFromResource: function(resourceJid) {
|
||||
var peerJid = null;
|
||||
Object.keys(this.members).some(function (jid) {
|
||||
peerJid = jid;
|
||||
return Strophe.getResourceFromJid(jid) === resourceJid;
|
||||
});
|
||||
return peerJid;
|
||||
}
|
||||
});
|
||||
|
|
21
toolbar.js
21
toolbar.js
|
@ -118,16 +118,17 @@ var Toolbar = (function (my) {
|
|||
|
||||
var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
|
||||
var subject = "Invitation to a Jitsi Meet (" + conferenceName + ")";
|
||||
var body = "Hey there, I%27d like to invite you to a Jitsi Meet"
|
||||
+ " conference I%27ve just set up.%0D%0A%0D%0A"
|
||||
+ "Please click on the following link in order"
|
||||
+ " to join the conference.%0D%0A%0D%0A"
|
||||
+ roomUrl + "%0D%0A%0D%0A"
|
||||
+ sharedKeyText
|
||||
+ "Note that Jitsi Meet is currently only supported by Chromium,"
|
||||
+ " Google Chrome and Opera, so you need"
|
||||
+ " to be using one of these browsers.%0D%0A%0D%0A"
|
||||
+ "Talk to you in a sec!";
|
||||
var body = "Hey there, I%27d like to invite you to a Jitsi Meet" +
|
||||
" conference I%27ve just set up.%0D%0A%0D%0A" +
|
||||
"Please click on the following link in order" +
|
||||
" to join the conference.%0D%0A%0D%0A" +
|
||||
roomUrl +
|
||||
"%0D%0A%0D%0A" +
|
||||
sharedKeyText +
|
||||
"Note that Jitsi Meet is currently only supported by Chromium," +
|
||||
" Google Chrome and Opera, so you need" +
|
||||
" to be using one of these browsers.%0D%0A%0D%0A" +
|
||||
"Talk to you in a sec!";
|
||||
|
||||
if (window.localStorage.displayname)
|
||||
body += "%0D%0A%0D%0A" + window.localStorage.displayname;
|
||||
|
|
4
util.js
4
util.js
|
@ -52,7 +52,9 @@ var Util = (function (my) {
|
|||
*/
|
||||
my.getAvailableVideoWidth = function () {
|
||||
var chatspaceWidth
|
||||
= $('#chatspace').is(":visible") ? $('#chatspace').width() : 0;
|
||||
= (Chat.isVisible() || ContactList.isVisible())
|
||||
? $('#chatspace').width()
|
||||
: 0;
|
||||
|
||||
return window.innerWidth - chatspaceWidth;
|
||||
};
|
||||
|
|
359
videolayout.js
359
videolayout.js
|
@ -1,6 +1,8 @@
|
|||
var VideoLayout = (function (my) {
|
||||
var preMuted = false;
|
||||
var currentDominantSpeaker = null;
|
||||
var lastNCount = config.channelLastN;
|
||||
var lastNEndpointsCache = [];
|
||||
|
||||
my.changeLocalAudio = function(stream) {
|
||||
connection.jingle.localAudio = stream;
|
||||
|
@ -52,7 +54,7 @@ var VideoLayout = (function (my) {
|
|||
// Add stream ended handler
|
||||
stream.onended = function () {
|
||||
localVideoContainer.removeChild(localVideo);
|
||||
VideoLayout.checkChangeLargeVideo(localVideo.src);
|
||||
VideoLayout.updateRemovedVideo(localVideo.src);
|
||||
};
|
||||
// Flip video x axis if needed
|
||||
flipXLocalVideo = flipX;
|
||||
|
@ -63,6 +65,7 @@ var VideoLayout = (function (my) {
|
|||
RTC.attachMediaStream(localVideoSelector, stream);
|
||||
|
||||
localVideoSrc = localVideo.src;
|
||||
|
||||
VideoLayout.updateLargeVideo(localVideoSrc, 0);
|
||||
};
|
||||
|
||||
|
@ -71,7 +74,7 @@ var VideoLayout = (function (my) {
|
|||
* another one instead.
|
||||
* @param removedVideoSrc src stream identifier of the video.
|
||||
*/
|
||||
my.checkChangeLargeVideo = function(removedVideoSrc) {
|
||||
my.updateRemovedVideo = function(removedVideoSrc) {
|
||||
if (removedVideoSrc === $('#largeVideo').attr('src')) {
|
||||
// this is currently displayed as large
|
||||
// pick the last visible video in the row
|
||||
|
@ -83,7 +86,8 @@ var VideoLayout = (function (my) {
|
|||
if (!pick) {
|
||||
console.info("Last visible video no longer exists");
|
||||
pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
|
||||
if (!pick) {
|
||||
|
||||
if (!pick || !pick.src) {
|
||||
// Try local video
|
||||
console.info("Fallback to local video...");
|
||||
pick = $('#remoteVideos>span>span>video').get(0);
|
||||
|
@ -182,8 +186,9 @@ var VideoLayout = (function (my) {
|
|||
= $('#participant_' + currentDominantSpeaker + '>video')
|
||||
.get(0);
|
||||
|
||||
if (dominantSpeakerVideo)
|
||||
if (dominantSpeakerVideo) {
|
||||
VideoLayout.updateLargeVideo(dominantSpeakerVideo.src, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -279,28 +284,42 @@ var VideoLayout = (function (my) {
|
|||
* in the document and creates it eventually.
|
||||
*
|
||||
* @param peerJid peer Jid to check.
|
||||
*
|
||||
* @return Returns <tt>true</tt> if the peer container exists,
|
||||
* <tt>false</tt> - otherwise
|
||||
*/
|
||||
my.ensurePeerContainerExists = function(peerJid) {
|
||||
var peerResource = Strophe.getResourceFromJid(peerJid);
|
||||
var videoSpanId = 'participant_' + peerResource;
|
||||
ContactList.ensureAddContact(peerJid);
|
||||
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var videoSpanId = 'participant_' + resourceJid;
|
||||
|
||||
if ($('#' + videoSpanId).length > 0) {
|
||||
// If there's been a focus change, make sure we add focus related
|
||||
// interface!!
|
||||
if (focus && $('#remote_popupmenu_' + peerResource).length <= 0)
|
||||
if (focus && $('#remote_popupmenu_' + resourceJid).length <= 0)
|
||||
addRemoteVideoMenu( peerJid,
|
||||
document.getElementById(videoSpanId));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
var container
|
||||
= VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId);
|
||||
|
||||
var container
|
||||
= VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId);
|
||||
var nickfield = document.createElement('span');
|
||||
nickfield.className = "nick";
|
||||
nickfield.appendChild(document.createTextNode(resourceJid));
|
||||
container.appendChild(nickfield);
|
||||
|
||||
var nickfield = document.createElement('span');
|
||||
nickfield.className = "nick";
|
||||
nickfield.appendChild(document.createTextNode(peerResource));
|
||||
container.appendChild(nickfield);
|
||||
VideoLayout.resizeThumbnails();
|
||||
// In case this is not currently in the last n we don't show it.
|
||||
if (lastNCount
|
||||
&& lastNCount > 0
|
||||
&& $('#remoteVideos>span').length >= lastNCount + 2) {
|
||||
showPeerContainer(resourceJid, false);
|
||||
}
|
||||
else
|
||||
VideoLayout.resizeThumbnails();
|
||||
}
|
||||
};
|
||||
|
||||
my.addRemoteVideoContainer = function(peerJid, spanId) {
|
||||
|
@ -321,9 +340,158 @@ var VideoLayout = (function (my) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Shows the display name for the given video.
|
||||
* Creates an audio or video stream element.
|
||||
*/
|
||||
my.setDisplayName = function(videoSpanId, displayName) {
|
||||
my.createStreamElement = function (sid, stream) {
|
||||
var isVideo = stream.getVideoTracks().length > 0;
|
||||
|
||||
var element = isVideo
|
||||
? document.createElement('video')
|
||||
: document.createElement('audio');
|
||||
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
|
||||
+ sid + '_' + stream.id;
|
||||
|
||||
element.id = id;
|
||||
element.autoplay = true;
|
||||
element.oncontextmenu = function () { return false; };
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
my.addRemoteStreamElement
|
||||
= function (container, sid, stream, peerJid, thessrc) {
|
||||
var newElementId = null;
|
||||
|
||||
var isVideo = stream.getVideoTracks().length > 0;
|
||||
|
||||
if (container) {
|
||||
var streamElement = VideoLayout.createStreamElement(sid, stream);
|
||||
newElementId = streamElement.id;
|
||||
|
||||
container.appendChild(streamElement);
|
||||
|
||||
var sel = $('#' + newElementId);
|
||||
sel.hide();
|
||||
|
||||
// If the container is currently visible we attach the stream.
|
||||
if (!isVideo
|
||||
|| (container.offsetParent !== null && isVideo)) {
|
||||
RTC.attachMediaStream(sel, stream);
|
||||
|
||||
if (isVideo)
|
||||
waitForRemoteVideo(sel, thessrc, stream);
|
||||
}
|
||||
|
||||
stream.onended = function () {
|
||||
console.log('stream ended', this);
|
||||
|
||||
VideoLayout.removeRemoteStreamElement(stream, container);
|
||||
|
||||
if (peerJid)
|
||||
ContactList.removeContact(peerJid);
|
||||
};
|
||||
|
||||
// Add click handler.
|
||||
container.onclick = function (event) {
|
||||
/*
|
||||
* FIXME It turns out that videoThumb may not exist (if there is
|
||||
* no actual video).
|
||||
*/
|
||||
var videoThumb = $('#' + container.id + '>video').get(0);
|
||||
|
||||
if (videoThumb)
|
||||
VideoLayout.handleVideoThumbClicked(videoThumb.src);
|
||||
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Add hover handler
|
||||
$(container).hover(
|
||||
function() {
|
||||
VideoLayout.showDisplayName(container.id, true);
|
||||
},
|
||||
function() {
|
||||
var videoSrc = null;
|
||||
if ($('#' + container.id + '>video')
|
||||
&& $('#' + container.id + '>video').length > 0) {
|
||||
videoSrc = $('#' + container.id + '>video').get(0).src;
|
||||
}
|
||||
|
||||
// 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'))
|
||||
VideoLayout.showDisplayName(container.id, false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return newElementId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the remote stream element corresponding to the given stream and
|
||||
* parent container.
|
||||
*
|
||||
* @param stream the stream
|
||||
* @param container
|
||||
*/
|
||||
my.removeRemoteStreamElement = function (stream, container) {
|
||||
if (!container)
|
||||
return;
|
||||
|
||||
var select = null;
|
||||
var removedVideoSrc = null;
|
||||
if (stream.getVideoTracks().length > 0) {
|
||||
select = $('#' + container.id + '>video');
|
||||
removedVideoSrc = select.get(0).src;
|
||||
}
|
||||
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)
|
||||
select.removed = true;
|
||||
select.remove();
|
||||
|
||||
var audioCount = $('#' + container.id + '>audio').length;
|
||||
var videoCount = $('#' + container.id + '>video').length;
|
||||
|
||||
if (!audioCount && !videoCount) {
|
||||
console.log("Remove whole user", container.id);
|
||||
// Remove whole container
|
||||
container.remove();
|
||||
Util.playSoundNotification('userLeft');
|
||||
VideoLayout.resizeThumbnails();
|
||||
}
|
||||
|
||||
if (removedVideoSrc)
|
||||
VideoLayout.updateRemovedVideo(removedVideoSrc);
|
||||
};
|
||||
|
||||
/**
|
||||
* Show/hide peer container for the given resourceJid.
|
||||
*/
|
||||
function showPeerContainer(resourceJid, isShow) {
|
||||
var peerContainer = $('#participant_' + resourceJid);
|
||||
|
||||
if (!peerContainer)
|
||||
return;
|
||||
|
||||
if (!peerContainer.is(':visible') && isShow)
|
||||
peerContainer.show();
|
||||
else if (peerContainer.is(':visible') && !isShow)
|
||||
peerContainer.hide();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the display name for the given video span id.
|
||||
*/
|
||||
function setDisplayName(videoSpanId, displayName) {
|
||||
var nameSpan = $('#' + videoSpanId + '>span.displayname');
|
||||
var defaultLocalDisplayName = "Me";
|
||||
var defaultRemoteDisplayName = "Speaker";
|
||||
|
@ -334,12 +502,12 @@ var VideoLayout = (function (my) {
|
|||
|
||||
if (nameSpanElement.id === 'localDisplayName' &&
|
||||
$('#localDisplayName').text() !== displayName) {
|
||||
if (displayName)
|
||||
if (displayName && displayName.length > 0)
|
||||
$('#localDisplayName').text(displayName + ' (me)');
|
||||
else
|
||||
$('#localDisplayName').text(defaultLocalDisplayName);
|
||||
} else {
|
||||
if (displayName)
|
||||
if (displayName && displayName.length > 0)
|
||||
$('#' + videoSpanId + '_name').text(displayName);
|
||||
else
|
||||
$('#' + videoSpanId + '_name').text(defaultRemoteDisplayName);
|
||||
|
@ -359,7 +527,7 @@ var VideoLayout = (function (my) {
|
|||
nameSpan.innerText = defaultRemoteDisplayName;
|
||||
}
|
||||
|
||||
if (displayName && displayName.length) {
|
||||
if (displayName && displayName.length > 0) {
|
||||
nameSpan.innerText = displayName;
|
||||
}
|
||||
|
||||
|
@ -434,11 +602,7 @@ var VideoLayout = (function (my) {
|
|||
* @param isShow indicates if the display name should be shown or hidden
|
||||
*/
|
||||
my.showDisplayName = function(videoSpanId, isShow) {
|
||||
// FIX: need to use noConflict of jquery, because apparently we're
|
||||
// using another library that uses $, which conflics with jquery and
|
||||
// sometimes objects are null because of that!!!!!!!!!
|
||||
// http://api.jquery.com/jQuery.noConflict/
|
||||
var nameSpan = jQuery('#' + videoSpanId + '>span.displayname').get(0);
|
||||
var nameSpan = $('#' + videoSpanId + '>span.displayname').get(0);
|
||||
if (isShow) {
|
||||
if (nameSpan && nameSpan.innerHTML && nameSpan.innerHTML.length)
|
||||
nameSpan.setAttribute("style", "display:inline-block;");
|
||||
|
@ -459,8 +623,6 @@ var VideoLayout = (function (my) {
|
|||
return;
|
||||
}
|
||||
|
||||
var nameSpan = $('#' + videoSpanId + '>span.displayname');
|
||||
|
||||
var statusSpan = $('#' + videoSpanId + '>span.status');
|
||||
if (!statusSpan.length) {
|
||||
//Add status span
|
||||
|
@ -721,6 +883,8 @@ var VideoLayout = (function (my) {
|
|||
|
||||
/**
|
||||
* Calculates the thumbnail size.
|
||||
*
|
||||
* @param videoSpaceWidth the width of the video space
|
||||
*/
|
||||
my.calculateThumbnailSize = function (videoSpaceWidth) {
|
||||
// Calculate the available height, which is the inner window height minus
|
||||
|
@ -729,11 +893,15 @@ var VideoLayout = (function (my) {
|
|||
// container used for highlighting shadow.
|
||||
var availableHeight = 100;
|
||||
|
||||
var numvids = $('#remoteVideos>span:visible').length;
|
||||
var numvids = 0;
|
||||
if (lastNCount && lastNCount > 0)
|
||||
numvids = lastNCount + 1;
|
||||
else
|
||||
numvids = $('#remoteVideos>span:visible').length;
|
||||
|
||||
// Remove the 3px borders arround videos and border around the remote
|
||||
// videos area
|
||||
var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 50;
|
||||
var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 70;
|
||||
|
||||
var availableWidth = availableWinWidth / numvids;
|
||||
var aspectRatio = 16.0 / 9.0;
|
||||
|
@ -851,6 +1019,20 @@ var VideoLayout = (function (my) {
|
|||
return currentDominantSpeaker;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the corresponding resource jid to the given peer container
|
||||
* DOM element.
|
||||
*
|
||||
* @return the corresponding resource jid to the given peer container
|
||||
* DOM element
|
||||
*/
|
||||
my.getPeerContainerResourceJid = function (containerElement) {
|
||||
var i = containerElement.id.indexOf('participant_');
|
||||
|
||||
if (i >= 0)
|
||||
return containerElement.id.substring(i + 12);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the remote video menu element for the given <tt>jid</tt> in the
|
||||
* given <tt>parentElement</tt>.
|
||||
|
@ -965,6 +1147,25 @@ var VideoLayout = (function (my) {
|
|||
VideoLayout.showVideoIndicator(videoSpanId, isMuted);
|
||||
});
|
||||
|
||||
/**
|
||||
* Display name changed.
|
||||
*/
|
||||
$(document).bind('displaynamechanged',
|
||||
function (event, jid, displayName, status) {
|
||||
if (jid === 'localVideoContainer'
|
||||
|| jid === connection.emuc.myroomjid) {
|
||||
setDisplayName('localVideoContainer',
|
||||
displayName);
|
||||
} else {
|
||||
VideoLayout.ensurePeerContainerExists(jid);
|
||||
|
||||
setDisplayName(
|
||||
'participant_' + Strophe.getResourceFromJid(jid),
|
||||
displayName,
|
||||
status);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* On dominant speaker changed event.
|
||||
*/
|
||||
|
@ -974,29 +1175,113 @@ var VideoLayout = (function (my) {
|
|||
=== Strophe.getResourceFromJid(connection.emuc.myroomjid))
|
||||
return;
|
||||
|
||||
// Obtain container for new dominant speaker.
|
||||
var container = document.getElementById(
|
||||
'participant_' + resourceJid);
|
||||
|
||||
// Update the current dominant speaker.
|
||||
if (resourceJid !== currentDominantSpeaker)
|
||||
currentDominantSpeaker = resourceJid;
|
||||
else
|
||||
return;
|
||||
|
||||
// Obtain container for new dominant speaker.
|
||||
var container = document.getElementById(
|
||||
'participant_' + resourceJid);
|
||||
|
||||
// Local video will not have container found, but that's ok
|
||||
// since we don't want to switch to local video.
|
||||
if (container && !focusedVideoSrc)
|
||||
{
|
||||
var video = container.getElementsByTagName("video");
|
||||
if (video.length)
|
||||
{
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* On last N change event.
|
||||
*
|
||||
* @param event the event that notified us
|
||||
* @param lastNEndpoints the list of last N endpoints
|
||||
* @param endpointsEnteringLastN the list currently entering last N
|
||||
* endpoints
|
||||
*/
|
||||
$(document).bind('lastnchanged', function ( event,
|
||||
lastNEndpoints,
|
||||
endpointsEnteringLastN,
|
||||
stream) {
|
||||
if (lastNCount !== lastNEndpoints.length)
|
||||
lastNCount = lastNEndpoints.length;
|
||||
|
||||
lastNEndpointsCache = lastNEndpoints;
|
||||
|
||||
$('#remoteVideos>span').each(function( index, element ) {
|
||||
var resourceJid = VideoLayout.getPeerContainerResourceJid(element);
|
||||
|
||||
if (resourceJid
|
||||
&& lastNEndpoints.length > 0
|
||||
&& lastNEndpoints.indexOf(resourceJid) < 0) {
|
||||
console.log("Remove from last N", resourceJid);
|
||||
showPeerContainer(resourceJid, false);
|
||||
}
|
||||
});
|
||||
|
||||
if (!endpointsEnteringLastN || endpointsEnteringLastN.length < 0)
|
||||
endpointsEnteringLastN = lastNEndpoints;
|
||||
|
||||
if (endpointsEnteringLastN && endpointsEnteringLastN.length > 0) {
|
||||
endpointsEnteringLastN.forEach(function (resourceJid) {
|
||||
|
||||
if (!$('#participant_' + resourceJid).is(':visible')) {
|
||||
console.log("Add to last N", resourceJid);
|
||||
showPeerContainer(resourceJid, true);
|
||||
|
||||
mediaStreams.some(function (mediaStream) {
|
||||
if (mediaStream.peerjid
|
||||
&& Strophe.getResourceFromJid(mediaStream.peerjid)
|
||||
=== resourceJid
|
||||
&& mediaStream.type === mediaStream.VIDEO_TYPE) {
|
||||
var sel = $('#participant_' + resourceJid + '>video');
|
||||
|
||||
RTC.attachMediaStream(sel, mediaStream.stream);
|
||||
waitForRemoteVideo(
|
||||
sel,
|
||||
mediaStream.ssrc,
|
||||
mediaStream.stream);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).bind('videoactive.jingle', function (event, videoelem) {
|
||||
if (videoelem.attr('id').indexOf('mixedmslabel') === -1) {
|
||||
// ignore mixedmslabela0 and v0
|
||||
|
||||
videoelem.show();
|
||||
VideoLayout.resizeThumbnails();
|
||||
|
||||
var videoParent = videoelem.parent();
|
||||
var parentResourceJid = null;
|
||||
if (videoParent)
|
||||
parentResourceJid
|
||||
= VideoLayout.getPeerContainerResourceJid(videoParent[0]);
|
||||
|
||||
// Update the large video to the last added video only if there's no
|
||||
// current dominant or focused speaker or update it to the current
|
||||
// dominant speaker.
|
||||
if ((!focusedVideoSrc && !VideoLayout.getDominantSpeakerResourceJid())
|
||||
|| (parentResourceJid
|
||||
&& VideoLayout.getDominantSpeakerResourceJid()
|
||||
=== parentResourceJid)) {
|
||||
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1);
|
||||
}
|
||||
|
||||
VideoLayout.showFocusIndicator();
|
||||
}
|
||||
});
|
||||
|
||||
return my;
|
||||
}(VideoLayout || {}));
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue