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.localVideo = newStream;
|
||||||
this._setSharingScreen(newStream);
|
this._setSharingScreen(newStream);
|
||||||
if (newStream) {
|
if (newStream) {
|
||||||
APP.UI.addLocalStream(newStream);
|
APP.UI.addLocalVideoStream(newStream);
|
||||||
}
|
}
|
||||||
this.setVideoMuteStatus(this.isLocalVideoMuted());
|
this.setVideoMuteStatus(this.isLocalVideoMuted());
|
||||||
})
|
})
|
||||||
|
@ -1304,9 +1304,6 @@ export default {
|
||||||
replaceLocalTrack(this.localAudio, newStream, room))
|
replaceLocalTrack(this.localAudio, newStream, room))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.localAudio = newStream;
|
this.localAudio = newStream;
|
||||||
if (newStream) {
|
|
||||||
APP.UI.addLocalStream(newStream);
|
|
||||||
}
|
|
||||||
this.setAudioMuteStatus(this.isLocalAudioMuted());
|
this.setAudioMuteStatus(this.isLocalAudioMuted());
|
||||||
})
|
})
|
||||||
.then(resolve)
|
.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
|
* @param {JitsiTrack} track stream to show
|
||||||
*/
|
*/
|
||||||
UI.addLocalStream = track => {
|
UI.addLocalVideoStream = track => {
|
||||||
switch (track.getType()) {
|
VideoLayout.changeLocalVideo(track);
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.
|
* Returns an array of all thumbnails in the filmstrip.
|
||||||
*
|
*
|
||||||
|
@ -86,43 +76,6 @@ function getLocalParticipant() {
|
||||||
return getLocalParticipantFromStore(APP.store.getState());
|
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 = {
|
const VideoLayout = {
|
||||||
init(emitter) {
|
init(emitter) {
|
||||||
eventEmitter = emitter;
|
eventEmitter = emitter;
|
||||||
|
@ -208,10 +161,6 @@ const VideoLayout = {
|
||||||
* and setting them assume the id is already set.
|
* and setting them assume the id is already set.
|
||||||
*/
|
*/
|
||||||
mucJoined() {
|
mucJoined() {
|
||||||
if (largeVideo && !largeVideo.id) {
|
|
||||||
this.updateLargeVideo(getLocalParticipant().id, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: replace this call with a generic update call once SmallVideo
|
// FIXME: replace this call with a generic update call once SmallVideo
|
||||||
// only contains a ReactElement. Then remove this call once the
|
// only contains a ReactElement. Then remove this call once the
|
||||||
// Filmstrip is fully in React.
|
// Filmstrip is fully in React.
|
||||||
|
@ -247,79 +196,6 @@ const VideoLayout = {
|
||||||
localVideoThumbnail.setVisible(visible);
|
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) {
|
onRemoteStreamAdded(stream) {
|
||||||
const id = stream.getParticipantId();
|
const id = stream.getParticipantId();
|
||||||
const remoteVideo = remoteVideos[id];
|
const remoteVideo = remoteVideos[id];
|
||||||
|
@ -423,23 +299,6 @@ const VideoLayout = {
|
||||||
|
|
||||||
getAllThumbnails().forEach(thumbnail =>
|
getAllThumbnails().forEach(thumbnail =>
|
||||||
thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
|
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, 'audio');
|
||||||
this.updateMutedForNoTracks(id, 'video');
|
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???
|
// FIXME: what does this do???
|
||||||
remoteVideoActive(videoElement, resourceJid) {
|
remoteVideoActive(videoElement, resourceJid) {
|
||||||
|
|
||||||
logger.info(`${resourceJid} video is now active`, videoElement);
|
logger.info(`${resourceJid} video is now active`, videoElement);
|
||||||
|
|
||||||
VideoLayout.resizeThumbnails(
|
VideoLayout.resizeThumbnails(
|
||||||
false, () => {
|
false, () => {
|
||||||
if (videoElement) {
|
if (videoElement) {
|
||||||
$(videoElement).show();
|
$(videoElement).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this._updateLargeVideoIfDisplayed(resourceJid, true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -646,10 +463,8 @@ const VideoLayout = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isCurrentlyOnLarge(id)) {
|
// large video will show avatar instead of muted stream
|
||||||
// large video will show avatar instead of muted stream
|
this._updateLargeVideoIfDisplayed(id, true);
|
||||||
this.updateLargeVideo(id, true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -677,18 +492,6 @@ const VideoLayout = {
|
||||||
onDominantSpeakerChanged(id) {
|
onDominantSpeakerChanged(id) {
|
||||||
getAllThumbnails().forEach(thumbnail =>
|
getAllThumbnails().forEach(thumbnail =>
|
||||||
thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
|
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) {
|
if (remoteVideo) {
|
||||||
remoteVideo.updateView();
|
remoteVideo.updateView();
|
||||||
if (remoteVideo.isCurrentlyOnLargeVideo()) {
|
this._updateLargeVideoIfDisplayed(id);
|
||||||
this.updateLargeVideo(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -809,7 +610,6 @@ const VideoLayout = {
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoLayout.resizeThumbnails();
|
VideoLayout.resizeThumbnails();
|
||||||
VideoLayout._updateAfterThumbRemoved(id);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onVideoTypeChanged(id, newVideoType) {
|
onVideoTypeChanged(id, newVideoType) {
|
||||||
|
@ -835,9 +635,7 @@ const VideoLayout = {
|
||||||
}
|
}
|
||||||
smallVideo.setVideoType(newVideoType);
|
smallVideo.setVideoType(newVideoType);
|
||||||
|
|
||||||
if (this.isCurrentlyOnLarge(id)) {
|
this._updateLargeVideoIfDisplayed(id, true);
|
||||||
this.updateLargeVideo(id, true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -124,9 +124,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
} else {
|
} else {
|
||||||
APP.UI.setVideoMuted(participantID, muted);
|
APP.UI.setVideoMuted(participantID, muted);
|
||||||
}
|
}
|
||||||
APP.UI.onPeerVideoTypeChanged(
|
APP.UI.onPeerVideoTypeChanged(participantID, jitsiTrack.videoType);
|
||||||
participantID,
|
|
||||||
jitsiTrack.videoType);
|
|
||||||
} else if (jitsiTrack.isLocal()) {
|
} else if (jitsiTrack.isLocal()) {
|
||||||
APP.conference.setAudioMuteStatus(muted);
|
APP.conference.setAudioMuteStatus(muted);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,3 +3,4 @@ export * from './components';
|
||||||
|
|
||||||
import './middleware';
|
import './middleware';
|
||||||
import './reducer';
|
import './reducer';
|
||||||
|
import './subscriber';
|
||||||
|
|
|
@ -38,7 +38,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CONFERENCE_JOINED:
|
||||||
case PARTICIPANT_JOINED:
|
case PARTICIPANT_JOINED:
|
||||||
case PARTICIPANT_LEFT:
|
case PARTICIPANT_LEFT:
|
||||||
case PIN_PARTICIPANT:
|
case PIN_PARTICIPANT:
|
||||||
|
@ -47,13 +47,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
store.dispatch(selectParticipantInLargeVideo());
|
store.dispatch(selectParticipantInLargeVideo());
|
||||||
break;
|
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:
|
case TRACK_UPDATED:
|
||||||
// In order to minimize re-calculations, we need to select participant
|
// In order to minimize re-calculations, we need to select participant
|
||||||
// only if the videoType of the current participant rendered in
|
// 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