ref(large-video): switch LargeVideo logic to react
This commit is contained in:
parent
625d268373
commit
21dcc41d31
|
@ -1253,7 +1253,7 @@ export default {
|
|||
this.localVideo = newStream;
|
||||
this._setSharingScreen(newStream);
|
||||
if (newStream) {
|
||||
APP.UI.addLocalStream(newStream);
|
||||
APP.UI.addLocalVideoStream(newStream);
|
||||
}
|
||||
this.setVideoMuteStatus(this.isLocalVideoMuted());
|
||||
})
|
||||
|
@ -1304,9 +1304,6 @@ export default {
|
|||
replaceLocalTrack(this.localAudio, newStream, room))
|
||||
.then(() => {
|
||||
this.localAudio = newStream;
|
||||
if (newStream) {
|
||||
APP.UI.addLocalStream(newStream);
|
||||
}
|
||||
this.setAudioMuteStatus(this.isLocalAudioMuted());
|
||||
})
|
||||
.then(resolve)
|
||||
|
|
|
@ -229,22 +229,11 @@ UI.unbindEvents = () => {
|
|||
};
|
||||
|
||||
/**
|
||||
* Show local stream on UI.
|
||||
* Show local video stream on UI.
|
||||
* @param {JitsiTrack} track stream to show
|
||||
*/
|
||||
UI.addLocalStream = track => {
|
||||
switch (track.getType()) {
|
||||
case 'audio':
|
||||
// Local audio is not rendered so no further action is needed at this
|
||||
// point.
|
||||
break;
|
||||
case 'video':
|
||||
VideoLayout.changeLocalVideo(track);
|
||||
break;
|
||||
default:
|
||||
logger.error(`Unknown stream type: ${track.getType()}`);
|
||||
break;
|
||||
}
|
||||
UI.addLocalVideoStream = track => {
|
||||
VideoLayout.changeLocalVideo(track);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,16 +53,6 @@ function onLocalFlipXChanged(val) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the redux representation of all known users.
|
||||
*
|
||||
* @private
|
||||
* @returns {Array}
|
||||
*/
|
||||
function getAllParticipants() {
|
||||
return APP.store.getState()['features/base/participants'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all thumbnails in the filmstrip.
|
||||
*
|
||||
|
@ -86,43 +76,6 @@ function getLocalParticipant() {
|
|||
return getLocalParticipantFromStore(APP.store.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user ID of the remote participant that is current the dominant
|
||||
* speaker.
|
||||
*
|
||||
* @private
|
||||
* @returns {string|null}
|
||||
*/
|
||||
function getCurrentRemoteDominantSpeakerID() {
|
||||
const dominantSpeaker = getAllParticipants()
|
||||
.find(participant => participant.dominantSpeaker);
|
||||
|
||||
if (dominantSpeaker) {
|
||||
return dominantSpeaker.local ? null : dominantSpeaker.id;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding resource id to the given peer container
|
||||
* DOM element.
|
||||
*
|
||||
* @return the corresponding resource id to the given peer container
|
||||
* DOM element
|
||||
*/
|
||||
function getPeerContainerResourceId(containerElement) {
|
||||
if (localVideoThumbnail.container === containerElement) {
|
||||
return localVideoThumbnail.id;
|
||||
}
|
||||
|
||||
const i = containerElement.id.indexOf('participant_');
|
||||
|
||||
if (i >= 0) {
|
||||
return containerElement.id.substring(i + 12);
|
||||
}
|
||||
}
|
||||
|
||||
const VideoLayout = {
|
||||
init(emitter) {
|
||||
eventEmitter = emitter;
|
||||
|
@ -208,10 +161,6 @@ const VideoLayout = {
|
|||
* and setting them assume the id is already set.
|
||||
*/
|
||||
mucJoined() {
|
||||
if (largeVideo && !largeVideo.id) {
|
||||
this.updateLargeVideo(getLocalParticipant().id, true);
|
||||
}
|
||||
|
||||
// FIXME: replace this call with a generic update call once SmallVideo
|
||||
// only contains a ReactElement. Then remove this call once the
|
||||
// Filmstrip is fully in React.
|
||||
|
@ -247,79 +196,6 @@ const VideoLayout = {
|
|||
localVideoThumbnail.setVisible(visible);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if removed video is currently displayed and tries to display
|
||||
* another one instead.
|
||||
* Uses focusedID if any or dominantSpeakerID if any,
|
||||
* otherwise elects new video, in this order.
|
||||
*/
|
||||
_updateAfterThumbRemoved(id) {
|
||||
// Always trigger an update if large video is empty.
|
||||
if (!largeVideo
|
||||
|| (this.getLargeVideoID() && !this.isCurrentlyOnLarge(id))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pinnedId = this.getPinnedId();
|
||||
let newId;
|
||||
|
||||
if (pinnedId) {
|
||||
newId = pinnedId;
|
||||
} else if (getCurrentRemoteDominantSpeakerID()) {
|
||||
newId = getCurrentRemoteDominantSpeakerID();
|
||||
} else { // Otherwise select last visible video
|
||||
newId = this.electLastVisibleVideo();
|
||||
}
|
||||
|
||||
this.updateLargeVideo(newId);
|
||||
},
|
||||
|
||||
electLastVisibleVideo() {
|
||||
// pick the last visible video in the row
|
||||
// if nobody else is left, this picks the local video
|
||||
const remoteThumbs = Filmstrip.getThumbs(true).remoteThumbs;
|
||||
let thumbs = remoteThumbs.filter('[id!="mixedstream"]');
|
||||
|
||||
const lastVisible = thumbs.filter(':visible:last');
|
||||
|
||||
if (lastVisible.length) {
|
||||
const id = getPeerContainerResourceId(lastVisible[0]);
|
||||
|
||||
if (remoteVideos[id]) {
|
||||
logger.info(`electLastVisibleVideo: ${id}`);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// The RemoteVideo was removed (but the DOM elements may still
|
||||
// exist).
|
||||
}
|
||||
|
||||
logger.info('Last visible video no longer exists');
|
||||
thumbs = Filmstrip.getThumbs().remoteThumbs;
|
||||
if (thumbs.length) {
|
||||
const id = getPeerContainerResourceId(thumbs[0]);
|
||||
|
||||
if (remoteVideos[id]) {
|
||||
logger.info(`electLastVisibleVideo: ${id}`);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// The RemoteVideo was removed (but the DOM elements may
|
||||
// still exist).
|
||||
}
|
||||
|
||||
// Go with local video
|
||||
logger.info('Fallback to local video...');
|
||||
|
||||
const { id } = getLocalParticipant();
|
||||
|
||||
logger.info(`electLastVisibleVideo: ${id}`);
|
||||
|
||||
return id;
|
||||
},
|
||||
|
||||
onRemoteStreamAdded(stream) {
|
||||
const id = stream.getParticipantId();
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
@ -423,23 +299,6 @@ const VideoLayout = {
|
|||
|
||||
getAllThumbnails().forEach(thumbnail =>
|
||||
thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
|
||||
|
||||
if (pinnedParticipantID) {
|
||||
this.updateLargeVideo(pinnedParticipantID);
|
||||
} else {
|
||||
const currentDominantSpeakerID
|
||||
= getCurrentRemoteDominantSpeakerID();
|
||||
|
||||
if (currentDominantSpeakerID) {
|
||||
this.updateLargeVideo(currentDominantSpeakerID);
|
||||
} else {
|
||||
// if there is no currentDominantSpeakerID, it can also be
|
||||
// that local participant is the dominant speaker
|
||||
// we should act as a participant has left and was on large
|
||||
// and we should choose somebody (electLastVisibleVideo)
|
||||
this.updateLargeVideo(this.electLastVisibleVideo());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -473,19 +332,6 @@ const VideoLayout = {
|
|||
|
||||
this.updateMutedForNoTracks(id, 'audio');
|
||||
this.updateMutedForNoTracks(id, 'video');
|
||||
|
||||
const remoteVideosCount = Object.keys(remoteVideos).length;
|
||||
|
||||
if (remoteVideosCount === 1) {
|
||||
window.setTimeout(() => {
|
||||
const updatedRemoteVideosCount
|
||||
= Object.keys(remoteVideos).length;
|
||||
|
||||
if (updatedRemoteVideosCount === 1 && remoteVideos[id]) {
|
||||
this._maybePlaceParticipantOnLargeVideo(id);
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -512,43 +358,14 @@ const VideoLayout = {
|
|||
|
||||
// FIXME: what does this do???
|
||||
remoteVideoActive(videoElement, resourceJid) {
|
||||
|
||||
logger.info(`${resourceJid} video is now active`, videoElement);
|
||||
|
||||
VideoLayout.resizeThumbnails(
|
||||
false, () => {
|
||||
if (videoElement) {
|
||||
$(videoElement).show();
|
||||
}
|
||||
});
|
||||
|
||||
this._maybePlaceParticipantOnLargeVideo(resourceJid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the large video to the last added video only if there's no current
|
||||
* dominant, focused speaker or update it to the current dominant speaker.
|
||||
*
|
||||
* @params {string} resourceJid - The id of the user to maybe display on
|
||||
* large video.
|
||||
* @returns {void}
|
||||
*/
|
||||
_maybePlaceParticipantOnLargeVideo(resourceJid) {
|
||||
const pinnedId = this.getPinnedId();
|
||||
|
||||
if ((!pinnedId
|
||||
&& !getCurrentRemoteDominantSpeakerID()
|
||||
&& this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE))
|
||||
|| pinnedId === resourceJid
|
||||
|| (!pinnedId && resourceJid
|
||||
&& getCurrentRemoteDominantSpeakerID() === resourceJid)
|
||||
|
||||
/* Playback started while we're on the stage - may need to update
|
||||
video source with the new stream */
|
||||
|| this.isCurrentlyOnLarge(resourceJid)) {
|
||||
|
||||
this.updateLargeVideo(resourceJid, true);
|
||||
}
|
||||
this._updateLargeVideoIfDisplayed(resourceJid, true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -646,10 +463,8 @@ const VideoLayout = {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.isCurrentlyOnLarge(id)) {
|
||||
// large video will show avatar instead of muted stream
|
||||
this.updateLargeVideo(id, true);
|
||||
}
|
||||
// large video will show avatar instead of muted stream
|
||||
this._updateLargeVideoIfDisplayed(id, true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -677,18 +492,6 @@ const VideoLayout = {
|
|||
onDominantSpeakerChanged(id) {
|
||||
getAllThumbnails().forEach(thumbnail =>
|
||||
thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
|
||||
|
||||
|
||||
if (!remoteVideos[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Local video will not have container found, but that's ok
|
||||
// since we don't want to switch to local video.
|
||||
if (!interfaceConfig.filmStripOnly && !this.getPinnedId()
|
||||
&& !this.getCurrentlyOnLargeContainer().stayOnStage()) {
|
||||
this.updateLargeVideo(id);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -758,9 +561,7 @@ const VideoLayout = {
|
|||
|
||||
if (remoteVideo) {
|
||||
remoteVideo.updateView();
|
||||
if (remoteVideo.isCurrentlyOnLargeVideo()) {
|
||||
this.updateLargeVideo(id);
|
||||
}
|
||||
this._updateLargeVideoIfDisplayed(id);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -809,7 +610,6 @@ const VideoLayout = {
|
|||
}
|
||||
|
||||
VideoLayout.resizeThumbnails();
|
||||
VideoLayout._updateAfterThumbRemoved(id);
|
||||
},
|
||||
|
||||
onVideoTypeChanged(id, newVideoType) {
|
||||
|
@ -835,9 +635,7 @@ const VideoLayout = {
|
|||
}
|
||||
smallVideo.setVideoType(newVideoType);
|
||||
|
||||
if (this.isCurrentlyOnLarge(id)) {
|
||||
this.updateLargeVideo(id, true);
|
||||
}
|
||||
this._updateLargeVideoIfDisplayed(id, true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -124,9 +124,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
} else {
|
||||
APP.UI.setVideoMuted(participantID, muted);
|
||||
}
|
||||
APP.UI.onPeerVideoTypeChanged(
|
||||
participantID,
|
||||
jitsiTrack.videoType);
|
||||
APP.UI.onPeerVideoTypeChanged(participantID, jitsiTrack.videoType);
|
||||
} else if (jitsiTrack.isLocal()) {
|
||||
APP.conference.setAudioMuteStatus(muted);
|
||||
} else {
|
||||
|
|
|
@ -3,3 +3,4 @@ export * from './components';
|
|||
|
||||
import './middleware';
|
||||
import './reducer';
|
||||
import './subscriber';
|
||||
|
|
|
@ -38,7 +38,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
case CONFERENCE_JOINED:
|
||||
case PARTICIPANT_JOINED:
|
||||
case PARTICIPANT_LEFT:
|
||||
case PIN_PARTICIPANT:
|
||||
|
@ -47,13 +47,6 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
store.dispatch(selectParticipantInLargeVideo());
|
||||
break;
|
||||
|
||||
case CONFERENCE_JOINED:
|
||||
// Ensure a participant is selected on conference join. This addresses
|
||||
// the case where video tracks were received before CONFERENCE_JOINED
|
||||
// fired; without the conference selection may not happen.
|
||||
store.dispatch(selectParticipant());
|
||||
break;
|
||||
|
||||
case TRACK_UPDATED:
|
||||
// In order to minimize re-calculations, we need to select participant
|
||||
// only if the videoType of the current participant rendered in
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||
|
||||
/**
|
||||
* Updates the on stage participant video.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => state['features/large-video'].participantId,
|
||||
/* listener */ participantId => {
|
||||
VideoLayout.updateLargeVideo(participantId, true);
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue