Make it possible to pin a participant from the contact list, even if he's not in the lastN set.

This commit is contained in:
George Politis 2014-11-24 15:58:50 +01:00
parent 71e290a8ad
commit 7da0fd6794
4 changed files with 128 additions and 35 deletions

19
app.js
View File

@ -238,6 +238,25 @@ function doJoin() {
} }
function waitForRemoteVideo(selector, ssrc, stream) { function waitForRemoteVideo(selector, ssrc, stream) {
// 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!
//
// The above way of doing things results in video SRCs that don't correspond
// to any SSRC for a short period of time (to be more precise, for as long
// the waitForRemoteVideo takes to complete). This causes problems (see
// bellow).
//
// I'm wondering why we need to do that; i.e. why call RTC.attachMediaStream()
// a second time in here and only then update the videoSrcToSsrc map? Why
// not simply update the videoSrcToSsrc map when the RTC.attachMediaStream()
// is called the first time? I actually do that in the lastN changed event
// handler because the "orphan" video SRC is causing troubles there. The
// purpose of this method would then be to fire the "videoactive.jingle".
//
// Food for though I guess :-)
if (selector.removed || !selector.parent().is(":visible")) { if (selector.removed || !selector.parent().is(":visible")) {
console.warn("Media removed before had started", selector); console.warn("Media removed before had started", selector);
return; return;

View File

@ -41,17 +41,13 @@ var ContactList = (function (my) {
var contactlist = $('#contactlist>ul'); var contactlist = $('#contactlist>ul');
var newContact = document.createElement('li'); var newContact = document.createElement('li');
// XXX(gp) contact click event handling is now in videolayout.js. Is the
// following statement (newContact.id = resourceJid) still relevant?
newContact.id = resourceJid; newContact.id = resourceJid;
newContact.className = "clickable"; newContact.className = "clickable";
newContact.onclick = function(event) { newContact.onclick = function(event) {
if(event.currentTarget.className === "clickable") { if(event.currentTarget.className === "clickable") {
var jid = event.currentTarget.id; $(ContactList).trigger('contactclicked', [peerJid]);
var videoContainer = $("#participant_" + jid);
if (videoContainer.length > 0) {
videoContainer.click();
} else if (jid == Strophe.getResourceFromJid(connection.emuc.myroomjid)) {
$("#localVideoContainer").click();
}
} }
}; };

View File

@ -37,7 +37,7 @@
<script src="app.js?v=20"></script><!-- application logic --> <script src="app.js?v=20"></script><!-- application logic -->
<script src="commands.js?v=1"></script><!-- application logic --> <script src="commands.js?v=1"></script><!-- application logic -->
<script src="chat.js?v=14"></script><!-- chat logic --> <script src="chat.js?v=14"></script><!-- chat logic -->
<script src="contact_list.js?v=5"></script><!-- contact list logic --> <script src="contact_list.js?v=6"></script><!-- contact list logic -->
<script src="util.js?v=6"></script><!-- utility functions --> <script src="util.js?v=6"></script><!-- utility functions -->
<script src="etherpad.js?v=9"></script><!-- etherpad plugin --> <script src="etherpad.js?v=9"></script><!-- etherpad plugin -->
<script src="prezi.js?v=6"></script><!-- prezi plugin --> <script src="prezi.js?v=6"></script><!-- prezi plugin -->
@ -47,7 +47,7 @@
<script src="analytics.js?v=1"></script><!-- google analytics plugin --> <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<script src="rtp_sts.js?v=5"></script><!-- RTP stats processing --> <script src="rtp_sts.js?v=5"></script><!-- RTP stats processing -->
<script src="local_sts.js?v=2"></script><!-- Local stats processing --> <script src="local_sts.js?v=2"></script><!-- Local stats processing -->
<script src="videolayout.js?v=27"></script><!-- video ui --> <script src="videolayout.js?v=28"></script><!-- video ui -->
<script src="connectionquality.js?v=1"></script> <script src="connectionquality.js?v=1"></script>
<script src="toolbar.js?v=6"></script><!-- toolbar ui --> <script src="toolbar.js?v=6"></script><!-- toolbar ui -->
<script src="toolbar_toggler.js?v=2"></script> <script src="toolbar_toggler.js?v=2"></script>

View File

@ -4,6 +4,7 @@ var VideoLayout = (function (my) {
var localLastNCount = config.channelLastN; var localLastNCount = config.channelLastN;
var localLastNSet = []; var localLastNSet = [];
var lastNEndpointsCache = []; var lastNEndpointsCache = [];
var lastNPickupJid = null;
var largeVideoState = { var largeVideoState = {
updateInProgress: false, updateInProgress: false,
newSrc: '' newSrc: ''
@ -238,7 +239,7 @@ var VideoLayout = (function (my) {
} }
}; };
my.handleVideoThumbClicked = function(videoSrc) { my.handleVideoThumbClicked = function(videoSrc, noPinnedEndpointChangedEvent) {
// Restore style for previously focused video // Restore style for previously focused video
var focusJid = getJidFromVideoSrc(focusedVideoSrc); var focusJid = getJidFromVideoSrc(focusedVideoSrc);
var oldContainer = getParticipantContainer(focusJid); var oldContainer = getParticipantContainer(focusJid);
@ -263,7 +264,9 @@ var VideoLayout = (function (my) {
} }
} }
$(document).trigger("pinnedendpointchanged"); if (!noPinnedEndpointChangedEvent) {
$(document).trigger("pinnedendpointchanged");
}
return; return;
} }
@ -277,7 +280,13 @@ var VideoLayout = (function (my) {
var container = getParticipantContainer(userJid); var container = getParticipantContainer(userJid);
container.addClass("videoContainerFocused"); container.addClass("videoContainerFocused");
$(document).trigger("pinnedendpointchanged", [userJid]); if (!noPinnedEndpointChangedEvent) {
$(document).trigger("pinnedendpointchanged", [userJid]);
}
}
if ($('#largeVideo').attr('src') == videoSrc) {
return;
} }
// Triggers a "video.selected" event. The "false" parameter indicates // Triggers a "video.selected" event. The "false" parameter indicates
@ -599,7 +608,9 @@ var VideoLayout = (function (my) {
VideoLayout.resizeThumbnails(); VideoLayout.resizeThumbnails();
} }
ContactList.setClickable(resourceJid, !isHide); // We want to be able to pin a participant from the contact list, even
// if he's not in the lastN set!
// ContactList.setClickable(resourceJid, !isHide);
}; };
@ -1271,6 +1282,48 @@ var VideoLayout = (function (my) {
popupmenuElement.appendChild(paddingSpan); popupmenuElement.appendChild(paddingSpan);
} }
/**
* On contact list item clicked.
*/
$(ContactList).bind('contactclicked', function(event, jid) {
if (!jid) {
return;
}
var resource = Strophe.getResourceFromJid(jid);
var videoContainer = $("#participant_" + resource);
if (videoContainer.length > 0) {
var videoThumb = $('video', videoContainer).get(0);
// It is not always the case that a videoThumb exists (if there is
// no actual video).
if (videoThumb) {
if (videoThumb.src && videoThumb.src != '') {
// We have a video src, great! Let's update the large video
// now.
VideoLayout.handleVideoThumbClicked(videoThumb.src);
} else {
// If we don't have a video src for jid, there's absolutely
// no point in calling handleVideoThumbClicked; Quite
// simply, it won't work because it needs an src to attach
// to the large video.
//
// Instead, we trigger the pinned endpoint changed event to
// let the bridge adjust its lastN set for myjid and store
// the pinned user in the lastNPickupJid variable to be
// picked up later by the lastN changed event handler.
lastNPickupJid = jid;
$(document).trigger("pinnedendpointchanged", [jid]);
}
} else if (jid == connection.emuc.myroomjid) {
$("#localVideoContainer").click();
}
}
});
/** /**
* On audio muted event. * On audio muted event.
*/ */
@ -1430,6 +1483,8 @@ var VideoLayout = (function (my) {
localLastNSet = nextLocalLastNSet; localLastNSet = nextLocalLastNSet;
var updateLargeVideo = false;
// Handle LastN/local LastN changes. // Handle LastN/local LastN changes.
$('#remoteVideos>span').each(function( index, element ) { $('#remoteVideos>span').each(function( index, element ) {
var resourceJid = VideoLayout.getPeerContainerResourceJid(element); var resourceJid = VideoLayout.getPeerContainerResourceJid(element);
@ -1455,28 +1510,8 @@ var VideoLayout = (function (my) {
// displayed in the large video we have to switch to another // displayed in the large video we have to switch to another
// user. // user.
var largeVideoResource = VideoLayout.getLargeVideoResource(); var largeVideoResource = VideoLayout.getLargeVideoResource();
if (resourceJid === largeVideoResource) { if (!updateLargeVideo && resourceJid === largeVideoResource) {
var resource, container, src; updateLargeVideo = true;
var myResource
= Strophe.getResourceFromJid(connection.emuc.myroomjid);
// Find out which endpoint to show in the large video.
for (var i = 0; i < lastNEndpoints.length; i++) {
resource = lastNEndpoints[i];
if (!resource || resource === myResource)
continue;
container = $("#participant_" + resource);
if (container.length == 0)
continue;
src = $('video', container).attr('src');
if (!src)
continue;
VideoLayout.updateLargeVideo(src);
break;
}
} }
} }
}); });
@ -1501,6 +1536,18 @@ var VideoLayout = (function (my) {
var videoStream = simulcast.getReceivingVideoStream(mediaStream.stream); var videoStream = simulcast.getReceivingVideoStream(mediaStream.stream);
RTC.attachMediaStream(sel, videoStream); RTC.attachMediaStream(sel, videoStream);
videoSrcToSsrc[sel.attr('src')] = mediaStream.ssrc;
if (lastNPickupJid == mediaStream.peerjid) {
// Clean up the lastN pickup jid.
lastNPickupJid = null;
// Don't fire the events again, they've already
// been fired in the contact list click handler.
VideoLayout.handleVideoThumbClicked($(sel).attr('src'), false);
updateLargeVideo = false;
}
waitForRemoteVideo( waitForRemoteVideo(
sel, sel,
mediaStream.ssrc, mediaStream.ssrc,
@ -1511,6 +1558,37 @@ var VideoLayout = (function (my) {
} }
}); });
} }
// The endpoint that was being shown in the large video has dropped out
// of the lastN set and there was no lastN pickup jid. We need to update
// the large video now.
if (updateLargeVideo) {
var resource, container, src;
var myResource
= Strophe.getResourceFromJid(connection.emuc.myroomjid);
// Find out which endpoint to show in the large video.
for (var i = 0; i < lastNEndpoints.length; i++) {
resource = lastNEndpoints[i];
if (!resource || resource === myResource)
continue;
container = $("#participant_" + resource);
if (container.length == 0)
continue;
src = $('video', container).attr('src');
if (!src)
continue;
// videoSrcToSsrc needs to be update for this call to succeed.
VideoLayout.updateLargeVideo(src);
break;
}
}
}); });
$(document).bind('videoactive.jingle', function (event, videoelem) { $(document).bind('videoactive.jingle', function (event, videoelem) {