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:
parent
71e290a8ad
commit
7da0fd6794
19
app.js
19
app.js
|
@ -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;
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
130
videolayout.js
130
videolayout.js
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue