import { _handleParticipantError } from '../base/conference';
import { MEDIA_TYPE, VIDEO_TYPE } from '../base/media';
import {
getLocalVideoTrack,
getTrackByMediaTypeAndParticipant
} from '../base/tracks';
import { SELECT_LARGE_VIDEO_PARTICIPANT } from './actionTypes';
/**
* Signals conference to select a participant.
*
* @returns {Function}
*/
export function selectParticipant() {
return (dispatch, getState) => {
const state = getState();
const conference = state['features/base/conference'].conference;
if (conference) {
const largeVideo = state['features/large-video'];
const tracks = state['features/base/tracks'];
const id = largeVideo.participantId;
const videoTrack
= getTrackByMediaTypeAndParticipant(
tracks,
MEDIA_TYPE.VIDEO,
id);
try {
conference.selectParticipant(
videoTrack && videoTrack.videoType === VIDEO_TYPE.CAMERA
? id
: null);
} catch (err) {
_handleParticipantError(err);
}
}
};
}
/**
* Action to select the participant to be displayed in LargeVideo based on a
* variety of factors: if there is a dominant or pinned speaker, or if there are
* remote tracks, etc.
*
* @returns {Function}
*/
export function selectParticipantInLargeVideo() {
return (dispatch, getState) => {
const state = getState();
const participantId = _electParticipantInLargeVideo(state);
const largeVideo = state['features/large-video'];
if (participantId !== largeVideo.participantId) {
dispatch({
type: SELECT_LARGE_VIDEO_PARTICIPANT,
participantId
});
dispatch(selectParticipant());
}
};
}
/**
* Returns the most recent existing video track. It can be local or remote
* video.
*
* @param {Track[]} tracks - All current tracks.
* @private
* @returns {(Track|undefined)}
*/
function _electLastVisibleVideo(tracks) {
// First we try to get most recent remote video track.
for (let i = tracks.length - 1; i >= 0; --i) {
const track = tracks[i];
if (!track.local && track.mediaType === MEDIA_TYPE.VIDEO) {
return track;
}
}
// And if no remote video tracks are available, we select the local one.
return getLocalVideoTrack(tracks);
}
/**
* Returns the identifier of the participant who is to be on the stage i.e.
* should be displayed in LargeVideo.
*
* @param {Object} state - The Redux state from which the participant to be
* displayed in LargeVideo is to be elected.
* @private
* @returns {(string|undefined)}
*/
function _electParticipantInLargeVideo(state) {
// First get the pinned participant. If the local participant is pinned,
// he/she will be shown in LargeVideo.
const participants = state['features/base/participants'];
let participant = participants.find(p => p.pinned);
let id = participant ? participant.id : undefined;
if (!id) {
// No participant is pinned so get the dominant speaker. But the local
// participant won't be displayed in LargeVideo even if he/she is the
// dominant speaker.
participant = participants.find(p => p.dominantSpeaker && !p.local);
if (participant) {
id = participant.id;
}
if (!id) {
// There is no dominant speaker so get the participant with the last
// visible video track. This may turn out to be the local
// participant.
const tracks = state['features/base/tracks'];
const videoTrack = _electLastVisibleVideo(tracks);
id = videoTrack && videoTrack.participantId;
}
}
return id;
}