Handle last n in the client (#1389)
* Handle last n in the client * fix(LargeVideoManager.js): Fixes check for low bandwidth. Needs more work * fix(LargeVideoManager.js): Fixes the Shared Video test. * fix(LargeVideoManager): Fix shared video view and remove last n checks. * fix(LargeVideoManager): Fixes jsdoc comment * fix(RemoteVideo): Fix connection status check * fix(LargeVideoManager,RemoteVideo): Syntax errors
This commit is contained in:
parent
d1050d6b02
commit
704e14f008
|
@ -1283,8 +1283,9 @@ export default {
|
||||||
*/
|
*/
|
||||||
room.on(
|
room.on(
|
||||||
ConferenceEvents.LAST_N_ENDPOINTS_CHANGED, (ids, enteringIds) => {
|
ConferenceEvents.LAST_N_ENDPOINTS_CHANGED, (ids, enteringIds) => {
|
||||||
APP.UI.handleLastNEndpoints(ids, enteringIds);
|
APP.UI.handleLastNEndpoints(ids, enteringIds);
|
||||||
});
|
});
|
||||||
|
|
||||||
room.on(
|
room.on(
|
||||||
ConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED,
|
ConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED,
|
||||||
(id, isActive) => {
|
(id, isActive) => {
|
||||||
|
@ -1940,5 +1941,18 @@ export default {
|
||||||
*/
|
*/
|
||||||
removeListener (eventName, listener) {
|
removeListener (eventName, listener) {
|
||||||
eventEmitter.removeListener(eventName, listener);
|
eventEmitter.removeListener(eventName, listener);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the participant given by participantId is currently in the
|
||||||
|
* last N set if there's one supported.
|
||||||
|
*
|
||||||
|
* @param participantId the identifier of the participant
|
||||||
|
* @returns {boolean} {true} if the participant given by the participantId
|
||||||
|
* is currently in the last N set or if there's no last N set at this point
|
||||||
|
* and {false} otherwise
|
||||||
|
*/
|
||||||
|
isInLastN (participantId) {
|
||||||
|
return room.isInLastN(participantId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -382,7 +382,9 @@
|
||||||
"FETCH_SESSION_ID": "Obtaining session-id...",
|
"FETCH_SESSION_ID": "Obtaining session-id...",
|
||||||
"GOT_SESSION_ID": "Obtaining session-id... Done",
|
"GOT_SESSION_ID": "Obtaining session-id... Done",
|
||||||
"GET_SESSION_ID_ERROR": "Get session-id error: __code__",
|
"GET_SESSION_ID_ERROR": "Get session-id error: __code__",
|
||||||
"USER_CONNECTION_INTERRUPTED": "__displayName__ is having connectivity issues..."
|
"USER_CONNECTION_INTERRUPTED": "__displayName__ is having connectivity issues...",
|
||||||
|
"LOW_BANDWIDTH": "Video for __displayName__ has been turned off to save bandwidth"
|
||||||
|
|
||||||
},
|
},
|
||||||
"recording":
|
"recording":
|
||||||
{
|
{
|
||||||
|
|
|
@ -348,17 +348,17 @@ ConnectionIndicator.prototype.remove = function() {
|
||||||
* the user is having connectivity issues.
|
* the user is having connectivity issues.
|
||||||
*/
|
*/
|
||||||
ConnectionIndicator.prototype.updateConnectionStatusIndicator
|
ConnectionIndicator.prototype.updateConnectionStatusIndicator
|
||||||
= function (isActive) {
|
= function (isActive) {
|
||||||
this.isConnectionActive = isActive;
|
this.isConnectionActive = isActive;
|
||||||
if (this.isConnectionActive) {
|
if (this.isConnectionActive) {
|
||||||
$(this.interruptedIndicator).hide();
|
$(this.interruptedIndicator).hide();
|
||||||
$(this.emptyIcon).show();
|
$(this.emptyIcon).show();
|
||||||
$(this.fullIcon).show();
|
$(this.fullIcon).show();
|
||||||
} else {
|
} else {
|
||||||
$(this.interruptedIndicator).show();
|
$(this.interruptedIndicator).show();
|
||||||
$(this.emptyIcon).hide();
|
$(this.emptyIcon).hide();
|
||||||
$(this.fullIcon).hide();
|
$(this.fullIcon).hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -127,7 +127,9 @@ export default class LargeVideoManager {
|
||||||
// the video was not rendered, before the connection has failed.
|
// the video was not rendered, before the connection has failed.
|
||||||
const isHavingConnectivityIssues
|
const isHavingConnectivityIssues
|
||||||
= APP.conference.isParticipantConnectionActive(id) === false;
|
= APP.conference.isParticipantConnectionActive(id) === false;
|
||||||
if (isHavingConnectivityIssues
|
|
||||||
|
if (videoType === VIDEO_CONTAINER_TYPE
|
||||||
|
&& isHavingConnectivityIssues
|
||||||
&& (isUserSwitch || !container.wasVideoRendered)) {
|
&& (isUserSwitch || !container.wasVideoRendered)) {
|
||||||
showAvatar = true;
|
showAvatar = true;
|
||||||
}
|
}
|
||||||
|
@ -155,10 +157,15 @@ export default class LargeVideoManager {
|
||||||
|
|
||||||
// Make sure no notification about remote failure is shown as
|
// Make sure no notification about remote failure is shown as
|
||||||
// its UI conflicts with the one for local connection interrupted.
|
// its UI conflicts with the one for local connection interrupted.
|
||||||
|
const isConnected = APP.conference.isConnectionInterrupted()
|
||||||
|
|| !isHavingConnectivityIssues;
|
||||||
|
|
||||||
this.updateParticipantConnStatusIndication(
|
this.updateParticipantConnStatusIndication(
|
||||||
id,
|
id,
|
||||||
APP.conference.isConnectionInterrupted()
|
isConnected,
|
||||||
|| !isHavingConnectivityIssues);
|
(isHavingConnectivityIssues)
|
||||||
|
? "connection.USER_CONNECTION_INTERRUPTED"
|
||||||
|
: "connection.LOW_BANDWIDTH");
|
||||||
|
|
||||||
// resolve updateLargeVideo promise after everything is done
|
// resolve updateLargeVideo promise after everything is done
|
||||||
promise.then(resolve);
|
promise.then(resolve);
|
||||||
|
@ -180,10 +187,11 @@ export default class LargeVideoManager {
|
||||||
* @param {string} id the id of remote participant(MUC nickname)
|
* @param {string} id the id of remote participant(MUC nickname)
|
||||||
* @param {boolean} isConnected true if the connection is active or false
|
* @param {boolean} isConnected true if the connection is active or false
|
||||||
* when the user is having connectivity issues.
|
* when the user is having connectivity issues.
|
||||||
|
* @param {string} messageKey the i18n key of the message
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
updateParticipantConnStatusIndication (id, isConnected) {
|
updateParticipantConnStatusIndication (id, isConnected, messageKey) {
|
||||||
|
|
||||||
// Apply grey filter on the large video
|
// Apply grey filter on the large video
|
||||||
this.videoContainer.showRemoteConnectionProblemIndicator(!isConnected);
|
this.videoContainer.showRemoteConnectionProblemIndicator(!isConnected);
|
||||||
|
@ -196,7 +204,7 @@ export default class LargeVideoManager {
|
||||||
let displayName
|
let displayName
|
||||||
= APP.conference.getParticipantDisplayName(id);
|
= APP.conference.getParticipantDisplayName(id);
|
||||||
this._setRemoteConnectionMessage(
|
this._setRemoteConnectionMessage(
|
||||||
"connection.USER_CONNECTION_INTERRUPTED",
|
messageKey,
|
||||||
{ displayName: displayName });
|
{ displayName: displayName });
|
||||||
|
|
||||||
// Show it now only if the VideoContainer is on top
|
// Show it now only if the VideoContainer is on top
|
||||||
|
@ -332,7 +340,7 @@ export default class LargeVideoManager {
|
||||||
*/
|
*/
|
||||||
showRemoteConnectionMessage (show) {
|
showRemoteConnectionMessage (show) {
|
||||||
if (typeof show !== 'boolean') {
|
if (typeof show !== 'boolean') {
|
||||||
show = APP.conference.isParticipantConnectionActive(this.id);
|
show = !APP.conference.isParticipantConnectionActive(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show) {
|
if (show) {
|
||||||
|
@ -458,7 +466,7 @@ export default class LargeVideoManager {
|
||||||
// "avatar" and "video connection" can not be displayed both
|
// "avatar" and "video connection" can not be displayed both
|
||||||
// at the same time, but the latter is of higher priority and it
|
// at the same time, but the latter is of higher priority and it
|
||||||
// will hide the avatar one if will be displayed.
|
// will hide the avatar one if will be displayed.
|
||||||
this.showRemoteConnectionMessage(/* fet the current state */);
|
this.showRemoteConnectionMessage(/* fetch the current state */);
|
||||||
this.showLocalConnectionMessage(/* fetch the current state */);
|
this.showLocalConnectionMessage(/* fetch the current state */);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -460,12 +460,12 @@ RemoteVideo.prototype.setMutedView = function(isMuted) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._figureOutMutedWhileDisconnected
|
RemoteVideo.prototype._figureOutMutedWhileDisconnected
|
||||||
= function(isDisconnected) {
|
= function(isDisconnected) {
|
||||||
if (isDisconnected && this.isVideoMuted) {
|
if (isDisconnected && this.isVideoMuted) {
|
||||||
this.mutedWhileDisconnected = true;
|
this.mutedWhileDisconnected = true;
|
||||||
} else if (!isDisconnected && !this.isVideoMuted) {
|
} else if (!isDisconnected && !this.isVideoMuted) {
|
||||||
this.mutedWhileDisconnected = false;
|
this.mutedWhileDisconnected = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -554,8 +554,7 @@ RemoteVideo.prototype.isVideoPlayable = function () {
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.updateView = function () {
|
RemoteVideo.prototype.updateView = function () {
|
||||||
|
|
||||||
this.updateConnectionStatusIndicator(
|
this.updateConnectionStatusIndicator();
|
||||||
null /* will obtain the status from 'conference' */);
|
|
||||||
|
|
||||||
// This must be called after 'updateConnectionStatusIndicator' because it
|
// This must be called after 'updateConnectionStatusIndicator' because it
|
||||||
// affects the display mode by modifying 'mutedWhileDisconnected' flag
|
// affects the display mode by modifying 'mutedWhileDisconnected' flag
|
||||||
|
@ -564,19 +563,13 @@ RemoteVideo.prototype.updateView = function () {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the UI to reflect user's connectivity status.
|
* Updates the UI to reflect user's connectivity status.
|
||||||
* @param isActive {boolean|null} 'true' if user's connection is active or
|
|
||||||
* 'false' when the use is having some connectivity issues and a warning
|
|
||||||
* should be displayed. When 'null' is passed then the current value will be
|
|
||||||
* obtained from the conference instance.
|
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.updateConnectionStatusIndicator = function (isActive) {
|
RemoteVideo.prototype.updateConnectionStatusIndicator = function () {
|
||||||
// Check for initial value if 'isActive' is not defined
|
const isActive = this.isConnectionActive();
|
||||||
if (typeof isActive !== "boolean") {
|
|
||||||
isActive = this.isConnectionActive();
|
if (isActive === null) {
|
||||||
if (isActive === null) {
|
// Cancel processing at this point - no update
|
||||||
// Cancel processing at this point - no update
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(this.id + " thumbnail is connection active ? " + isActive);
|
logger.debug(this.id + " thumbnail is connection active ? " + isActive);
|
||||||
|
@ -700,44 +693,6 @@ RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Show/hide peer container for the given id.
|
|
||||||
*/
|
|
||||||
RemoteVideo.prototype.showPeerContainer = function (state) {
|
|
||||||
if (!this.container)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var isHide = state === 'hide';
|
|
||||||
var resizeThumbnails = false;
|
|
||||||
|
|
||||||
if (!isHide) {
|
|
||||||
if (!$(this.container).is(':visible')) {
|
|
||||||
resizeThumbnails = true;
|
|
||||||
$(this.container).show();
|
|
||||||
}
|
|
||||||
// Call updateView, so that we'll figure out if avatar
|
|
||||||
// should be displayed based on video muted status and whether or not
|
|
||||||
// it's in the lastN set
|
|
||||||
this.updateView();
|
|
||||||
}
|
|
||||||
else if ($(this.container).is(':visible') && isHide)
|
|
||||||
{
|
|
||||||
resizeThumbnails = true;
|
|
||||||
$(this.container).hide();
|
|
||||||
if(this.connectionIndicator)
|
|
||||||
this.connectionIndicator.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resizeThumbnails) {
|
|
||||||
this.VideoLayout.resizeThumbnails();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to be able to pin a participant from the contact list, even
|
|
||||||
// if he's not in the lastN set!
|
|
||||||
// ContactList.setClickable(id, !isHide);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
RemoteVideo.prototype.updateResolution = function (resolution) {
|
RemoteVideo.prototype.updateResolution = function (resolution) {
|
||||||
if (this.connectionIndicator) {
|
if (this.connectionIndicator) {
|
||||||
this.connectionIndicator.updateResolution(resolution);
|
this.connectionIndicator.updateResolution(resolution);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global $, JitsiMeetJS, interfaceConfig */
|
/* global $, APP, JitsiMeetJS, interfaceConfig */
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||||
|
|
||||||
import Avatar from "../avatar/Avatar";
|
import Avatar from "../avatar/Avatar";
|
||||||
|
@ -446,7 +446,7 @@ SmallVideo.prototype.isCurrentlyOnLargeVideo = function () {
|
||||||
SmallVideo.prototype.isVideoPlayable = function() {
|
SmallVideo.prototype.isVideoPlayable = function() {
|
||||||
return this.videoStream // Is there anything to display ?
|
return this.videoStream // Is there anything to display ?
|
||||||
&& !this.isVideoMuted && !this.videoStream.isMuted() // Muted ?
|
&& !this.isVideoMuted && !this.videoStream.isMuted() // Muted ?
|
||||||
&& (this.isLocal || this.VideoLayout.isInLastN(this.id));
|
&& (this.isLocal || APP.conference.isInLastN(this.id));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global config, APP, $, interfaceConfig */
|
/* global APP, $, interfaceConfig */
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||||
|
|
||||||
import FilmStrip from "./FilmStrip";
|
import FilmStrip from "./FilmStrip";
|
||||||
|
@ -14,10 +14,6 @@ var remoteVideos = {};
|
||||||
var localVideoThumbnail = null;
|
var localVideoThumbnail = null;
|
||||||
|
|
||||||
var currentDominantSpeaker = null;
|
var currentDominantSpeaker = null;
|
||||||
var localLastNCount = config.channelLastN;
|
|
||||||
var localLastNSet = [];
|
|
||||||
var lastNEndpointsCache = [];
|
|
||||||
var lastNPickupId = null;
|
|
||||||
|
|
||||||
var eventEmitter = null;
|
var eventEmitter = null;
|
||||||
|
|
||||||
|
@ -60,8 +56,6 @@ function onContactClicked (id) {
|
||||||
// let the bridge adjust its lastN set for myjid and store
|
// let the bridge adjust its lastN set for myjid and store
|
||||||
// the pinned user in the lastNPickupId variable to be
|
// the pinned user in the lastNPickupId variable to be
|
||||||
// picked up later by the lastN changed event handler.
|
// picked up later by the lastN changed event handler.
|
||||||
|
|
||||||
lastNPickupId = id;
|
|
||||||
eventEmitter.emit(UIEvents.PINNED_ENDPOINT, remoteVideo, true);
|
eventEmitter.emit(UIEvents.PINNED_ENDPOINT, remoteVideo, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,8 +108,6 @@ var VideoLayout = {
|
||||||
// the local video thumb maybe one pixel
|
// the local video thumb maybe one pixel
|
||||||
this.resizeThumbnails(false, true);
|
this.resizeThumbnails(false, true);
|
||||||
|
|
||||||
this.lastNCount = config.channelLastN;
|
|
||||||
|
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -162,14 +154,6 @@ var VideoLayout = {
|
||||||
largeVideo.updateLargeVideoAudioLevel(lvl);
|
largeVideo.updateLargeVideoAudioLevel(lvl);
|
||||||
},
|
},
|
||||||
|
|
||||||
isInLastN (resource) {
|
|
||||||
return this.lastNCount < 0 || // lastN is disabled
|
|
||||||
// lastNEndpoints cache not built yet
|
|
||||||
(this.lastNCount > 0 && !lastNEndpointsCache.length) ||
|
|
||||||
(lastNEndpointsCache &&
|
|
||||||
lastNEndpointsCache.indexOf(resource) !== -1);
|
|
||||||
},
|
|
||||||
|
|
||||||
changeLocalAudio (stream) {
|
changeLocalAudio (stream) {
|
||||||
let localAudio = document.getElementById('localAudio');
|
let localAudio = document.getElementById('localAudio');
|
||||||
localAudio = stream.attach(localAudio);
|
localAudio = stream.attach(localAudio);
|
||||||
|
@ -457,13 +441,8 @@ var VideoLayout = {
|
||||||
remoteVideo.setVideoType(VIDEO_CONTAINER_TYPE);
|
remoteVideo.setVideoType(VIDEO_CONTAINER_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case this is not currently in the last n we don't show it.
|
VideoLayout.resizeThumbnails(false, true);
|
||||||
if (localLastNCount && localLastNCount > 0 &&
|
|
||||||
FilmStrip.getThumbs().remoteThumbs.length >= localLastNCount + 2) {
|
|
||||||
remoteVideo.showPeerContainer('hide');
|
|
||||||
} else {
|
|
||||||
VideoLayout.resizeThumbnails(false, true);
|
|
||||||
}
|
|
||||||
// Initialize the view
|
// Initialize the view
|
||||||
remoteVideo.updateView();
|
remoteVideo.updateView();
|
||||||
},
|
},
|
||||||
|
@ -713,142 +692,22 @@ var VideoLayout = {
|
||||||
* endpoints
|
* endpoints
|
||||||
*/
|
*/
|
||||||
onLastNEndpointsChanged (lastNEndpoints, endpointsEnteringLastN) {
|
onLastNEndpointsChanged (lastNEndpoints, endpointsEnteringLastN) {
|
||||||
if (this.lastNCount !== lastNEndpoints.length)
|
|
||||||
this.lastNCount = lastNEndpoints.length;
|
|
||||||
|
|
||||||
lastNEndpointsCache = lastNEndpoints;
|
Object.keys(remoteVideos).forEach(
|
||||||
|
id => {
|
||||||
|
if (lastNEndpoints.length > 0
|
||||||
|
&& lastNEndpoints.indexOf(id) < 0
|
||||||
|
|| endpointsEnteringLastN.length > 0
|
||||||
|
&& endpointsEnteringLastN.indexOf(id) > 0) {
|
||||||
|
|
||||||
// Say A, B, C, D, E, and F are in a conference and LastN = 3.
|
let remoteVideo = (id) ? remoteVideos[id] : null;
|
||||||
//
|
if (remoteVideo) {
|
||||||
// If LastN drops to, say, 2, because of adaptivity, then E should see
|
remoteVideo.updateView();
|
||||||
// thumbnails for A, B and C. A and B are in E's server side LastN set,
|
if (remoteVideo.isCurrentlyOnLargeVideo())
|
||||||
// so E sees them. C is only in E's local LastN set.
|
this.updateLargeVideo(id);
|
||||||
//
|
|
||||||
// If F starts talking and LastN = 3, then E should see thumbnails for
|
|
||||||
// F, A, B. B gets "ejected" from E's server side LastN set, but it
|
|
||||||
// enters E's local LastN ejecting C.
|
|
||||||
|
|
||||||
// Increase the local LastN set size, if necessary.
|
|
||||||
if (this.lastNCount > localLastNCount) {
|
|
||||||
localLastNCount = this.lastNCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the local LastN set preserving the order in which the
|
|
||||||
// endpoints appeared in the LastN/local LastN set.
|
|
||||||
var nextLocalLastNSet = lastNEndpoints.slice(0);
|
|
||||||
for (var i = 0; i < localLastNSet.length; i++) {
|
|
||||||
if (nextLocalLastNSet.length >= localLastNCount) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourceJid = localLastNSet[i];
|
|
||||||
if (nextLocalLastNSet.indexOf(resourceJid) === -1) {
|
|
||||||
nextLocalLastNSet.push(resourceJid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
localLastNSet = nextLocalLastNSet;
|
|
||||||
var updateLargeVideo = false;
|
|
||||||
|
|
||||||
// Handle LastN/local LastN changes.
|
|
||||||
FilmStrip.getThumbs().remoteThumbs.each(( index, element ) => {
|
|
||||||
var resourceJid = getPeerContainerResourceId(element);
|
|
||||||
var smallVideo = remoteVideos[resourceJid];
|
|
||||||
|
|
||||||
// We do not want to process any logic for our own(local) video
|
|
||||||
// because the local participant is never in the lastN set.
|
|
||||||
// The code of this function might detect that the local participant
|
|
||||||
// has been dropped out of the lastN set and will update the large
|
|
||||||
// video
|
|
||||||
// Detected from avatar tests, where lastN event override
|
|
||||||
// local video pinning
|
|
||||||
if(APP.conference.isLocalId(resourceJid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var isReceived = true;
|
|
||||||
if (resourceJid &&
|
|
||||||
lastNEndpoints.indexOf(resourceJid) < 0 &&
|
|
||||||
localLastNSet.indexOf(resourceJid) < 0) {
|
|
||||||
logger.log("Remove from last N", resourceJid);
|
|
||||||
if (smallVideo)
|
|
||||||
smallVideo.showPeerContainer('hide');
|
|
||||||
else if (!APP.conference.isLocalId(resourceJid))
|
|
||||||
logger.error("No remote video for: " + resourceJid);
|
|
||||||
isReceived = false;
|
|
||||||
} else if (resourceJid &&
|
|
||||||
//TOFIX: smallVideo may be undefined
|
|
||||||
smallVideo.isVisible() &&
|
|
||||||
lastNEndpoints.indexOf(resourceJid) < 0 &&
|
|
||||||
localLastNSet.indexOf(resourceJid) >= 0) {
|
|
||||||
|
|
||||||
// TOFIX: if we're here we already know that the smallVideo
|
|
||||||
// exists. Look at the previous FIX above.
|
|
||||||
if (smallVideo)
|
|
||||||
smallVideo.showPeerContainer('avatar');
|
|
||||||
else if (!APP.conference.isLocalId(resourceJid))
|
|
||||||
logger.error("No remote video for: " + resourceJid);
|
|
||||||
isReceived = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isReceived) {
|
|
||||||
// resourceJid has dropped out of the server side lastN set, so
|
|
||||||
// it is no longer being received. If resourceJid was being
|
|
||||||
// displayed in the large video we have to switch to another
|
|
||||||
// user.
|
|
||||||
if (!updateLargeVideo &&
|
|
||||||
this.isCurrentlyOnLarge(resourceJid)) {
|
|
||||||
updateLargeVideo = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!endpointsEnteringLastN || endpointsEnteringLastN.length < 0)
|
|
||||||
endpointsEnteringLastN = lastNEndpoints;
|
|
||||||
|
|
||||||
if (endpointsEnteringLastN && endpointsEnteringLastN.length > 0) {
|
|
||||||
endpointsEnteringLastN.forEach(function (resourceJid) {
|
|
||||||
|
|
||||||
var remoteVideo = remoteVideos[resourceJid];
|
|
||||||
if (remoteVideo)
|
|
||||||
remoteVideo.showPeerContainer('show');
|
|
||||||
|
|
||||||
if (!remoteVideo.isVisible()) {
|
|
||||||
logger.log("Add to last N", resourceJid);
|
|
||||||
|
|
||||||
remoteVideo.addRemoteStreamElement(remoteVideo.videoStream);
|
|
||||||
|
|
||||||
if (lastNPickupId == resourceJid) {
|
|
||||||
// Clean up the lastN pickup id.
|
|
||||||
lastNPickupId = null;
|
|
||||||
|
|
||||||
VideoLayout.handleVideoThumbClicked(resourceJid);
|
|
||||||
|
|
||||||
updateLargeVideo = false;
|
|
||||||
}
|
}
|
||||||
remoteVideo.waitForPlayback(
|
|
||||||
remoteVideo.selectVideoElement()[0],
|
|
||||||
remoteVideo.videoStream);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
// Find out which endpoint to show in the large video.
|
|
||||||
for (i = 0; i < lastNEndpoints.length; i++) {
|
|
||||||
resource = lastNEndpoints[i];
|
|
||||||
if (!resource || APP.conference.isLocalId(resource))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// videoSrcToSsrc needs to be update for this call to succeed.
|
|
||||||
this.updateLargeVideo(resource);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue