diff --git a/react/features/base/participants/components/ParticipantView.native.js b/react/features/base/participants/components/ParticipantView.native.js index 7c0dd6f99..8978facee 100644 --- a/react/features/base/participants/components/ParticipantView.native.js +++ b/react/features/base/participants/components/ParticipantView.native.js @@ -9,7 +9,6 @@ import { translate } from '../../i18n'; import { JitsiParticipantConnectionStatus } from '../../lib-jitsi-meet'; import { MEDIA_TYPE, - shouldRenderVideoTrack, VideoTrack } from '../../media'; import { Container, TintedView } from '../../react'; @@ -20,7 +19,8 @@ import Avatar from './Avatar'; import { getAvatarURL, getParticipantById, - getParticipantDisplayName + getParticipantDisplayName, + shouldRenderParticipantVideo } from '../functions'; import styles from './styles'; @@ -29,14 +29,6 @@ import styles from './styles'; */ type Props = { - /** - * The indicator which determines whether conferencing is in audio-only - * mode. - * - * @private - */ - _audioOnly: boolean, - /** * The source (e.g. URI, URL) of the avatar image of the participant with * {@link #participantId}. @@ -61,6 +53,11 @@ type Props = { */ _participantName: string, + /** + * True if the video should be rendered, false otherwise. + */ + _renderVideo: boolean, + /** * The video Track of the participant with {@link #participantId}. */ @@ -192,23 +189,11 @@ class ParticipantView extends Component { onPress, _avatar: avatar, _connectionStatus: connectionStatus, + _renderVideo: renderVideo, _videoTrack: videoTrack } = this.props; - // Is the video to be rendered? - // FIXME It's currently impossible to have true as the value of - // waitForVideoStarted because videoTrack's state videoStarted will be - // updated only after videoTrack is rendered. - // XXX Note that, unlike on web, we don't render video when the - // connection status is interrupted, this is because the renderer - // doesn't retain the last frame forever, so we would end up with a - // black screen. const waitForVideoStarted = false; - const renderVideo - = !this.props._audioOnly - && (connectionStatus - === JitsiParticipantConnectionStatus.ACTIVE) - && shouldRenderVideoTrack(videoTrack, waitForVideoStarted); // Is the avatar to be rendered? const renderAvatar = Boolean(!renderVideo && avatar); @@ -271,10 +256,10 @@ class ParticipantView extends Component { * associated (instance of) {@code ParticipantView}. * @private * @returns {{ - * _audioOnly: boolean, * _avatar: string, * _connectionStatus: string, * _participantName: string, + * _renderVideo: boolean, * _videoTrack: Track * }} */ @@ -308,12 +293,12 @@ function _mapStateToProps(state, ownProps) { } return { - _audioOnly: state['features/base/conference'].audioOnly, _avatar: avatar, _connectionStatus: connectionStatus || JitsiParticipantConnectionStatus.ACTIVE, _participantName: participantName, + _renderVideo: shouldRenderParticipantVideo(state, participantId), _videoTrack: getTrackByMediaTypeAndParticipant( state['features/base/tracks'], diff --git a/react/features/base/participants/functions.js b/react/features/base/participants/functions.js index c1d2c3764..025bb6bf3 100644 --- a/react/features/base/participants/functions.js +++ b/react/features/base/participants/functions.js @@ -3,6 +3,10 @@ import { getAvatarURL as _getAvatarURL } from 'js-utils/avatar'; import { toState } from '../redux'; +import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet'; +import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media'; +import { getTrackByMediaTypeAndParticipant } from '../tracks'; + import { DEFAULT_AVATAR_RELATIVE_PATH, LOCAL_PARTICIPANT_DEFAULT_ID, @@ -121,7 +125,8 @@ export function getNormalizedDisplayName(name: string) { * @private * @returns {(Participant|undefined)} */ -export function getParticipantById(stateful: Object | Function, id: string) { +export function getParticipantById( + stateful: Object | Function, id: string): ?Object { const participants = _getAllParticipants(stateful); return participants.find(p => p.id === id); @@ -276,3 +281,45 @@ export function isLocalParticipantModerator(stateful: Object | Function) { && (!state['features/base/config'].enableUserRolesBasedOnToken || !state['features/base/jwt'].isGuest)); } + +/** + * Returns true if the video of the participant should be rendered. + * + * @param {Object|Function} stateful - Object or function that can be resolved + * to the Redux state. + * @param {string} id - The ID of the participant. + * @returns {boolean} + */ +export function shouldRenderParticipantVideo( + stateful: Object | Function, id: string) { + const state = toState(stateful); + const participant = getParticipantById(state, id); + + if (!participant) { + return false; + } + + const audioOnly = state['features/base/conference'].audioOnly; + const connectionStatus = participant.connectionStatus + || JitsiParticipantConnectionStatus.ACTIVE; + const videoTrack = getTrackByMediaTypeAndParticipant( + state['features/base/tracks'], + MEDIA_TYPE.VIDEO, + id); + + // Is the video to be rendered? + // FIXME It's currently impossible to have true as the value of + // waitForVideoStarted because videoTrack's state videoStarted will be + // updated only after videoTrack is rendered. + // XXX Note that, unlike on web, we don't render video when the + // connection status is interrupted, this is because the renderer + // doesn't retain the last frame forever, so we would end up with a + // black screen. + const waitForVideoStarted = false; + + return !audioOnly + && (connectionStatus + === JitsiParticipantConnectionStatus.ACTIVE) + && shouldRenderVideoTrack(videoTrack, waitForVideoStarted); + +}