fix(multi-stream): Add a virtual SS tile on RN.

Add a second virtual SS tile on RN when a remote participant that has multi-stream mode enabled starts a screenshare.
This commit is contained in:
Jaya Allamsetty 2022-05-19 14:52:08 -04:00
parent 43b0118ff8
commit a707022d0b
6 changed files with 47 additions and 22 deletions

View File

@ -5,6 +5,7 @@ import { Text, View } from 'react-native';
import { SharedVideo } from '../../../shared-video/components/native'; import { SharedVideo } from '../../../shared-video/components/native';
import { Avatar } from '../../avatar'; import { Avatar } from '../../avatar';
import { getMultipleVideoSupportFeatureFlag } from '../../config/';
import { translate } from '../../i18n'; import { translate } from '../../i18n';
import { JitsiParticipantConnectionStatus } from '../../lib-jitsi-meet'; import { JitsiParticipantConnectionStatus } from '../../lib-jitsi-meet';
import { import {
@ -14,7 +15,7 @@ import {
import { Container, TintedView } from '../../react'; import { Container, TintedView } from '../../react';
import { connect } from '../../redux'; import { connect } from '../../redux';
import { TestHint } from '../../testing/components'; import { TestHint } from '../../testing/components';
import { getTrackByMediaTypeAndParticipant } from '../../tracks'; import { getTrackByMediaTypeAndParticipant, getVirtualScreenshareParticipantTrack } from '../../tracks';
import { shouldRenderParticipantVideo, getParticipantById } from '../functions'; import { shouldRenderParticipantVideo, getParticipantById } from '../functions';
import styles from './styles'; import styles from './styles';
@ -251,8 +252,12 @@ class ParticipantView extends Component<Props> {
function _mapStateToProps(state, ownProps) { function _mapStateToProps(state, ownProps) {
const { disableVideo, participantId } = ownProps; const { disableVideo, participantId } = ownProps;
const participant = getParticipantById(state, participantId); const participant = getParticipantById(state, participantId);
const tracks = state['features/base/tracks'];
let connectionStatus; let connectionStatus;
let participantName; let participantName;
const videoTrack = getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant
? getVirtualScreenshareParticipantTrack(tracks, participantId)
: getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
return { return {
_connectionStatus: _connectionStatus:
@ -261,11 +266,7 @@ function _mapStateToProps(state, ownProps) {
_isFakeParticipant: participant && participant.isFakeParticipant, _isFakeParticipant: participant && participant.isFakeParticipant,
_participantName: participantName, _participantName: participantName,
_renderVideo: shouldRenderParticipantVideo(state, participantId) && !disableVideo, _renderVideo: shouldRenderParticipantVideo(state, participantId) && !disableVideo,
_videoTrack: _videoTrack: videoTrack
getTrackByMediaTypeAndParticipant(
state['features/base/tracks'],
MEDIA_TYPE.VIDEO,
participantId)
}; };
} }

View File

@ -10,7 +10,11 @@ import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag }
import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet'; import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media'; import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
import { toState } from '../redux'; import { toState } from '../redux';
import { getScreenShareTrack, getTrackByMediaTypeAndParticipant } from '../tracks'; import {
getScreenShareTrack,
getTrackByMediaTypeAndParticipant,
getVirtualScreenshareParticipantTrack
} from '../tracks';
import { createDeferred } from '../util'; import { createDeferred } from '../util';
import { JIGASI_PARTICIPANT_ICON, MAX_DISPLAY_NAME_LENGTH, PARTICIPANT_ROLE } from './constants'; import { JIGASI_PARTICIPANT_ICON, MAX_DISPLAY_NAME_LENGTH, PARTICIPANT_ROLE } from './constants';
@ -478,8 +482,14 @@ export function shouldRenderParticipantVideo(stateful: Object | Function, id: st
} }
/* First check if we have an unmuted video track. */ /* First check if we have an unmuted video track. */
const videoTrack const tracks = state['features/base/tracks'];
= getTrackByMediaTypeAndParticipant(state['features/base/tracks'], MEDIA_TYPE.VIDEO, id); let videoTrack;
if (getMultipleVideoSupportFeatureFlag(state) && participant.isVirtualScreenshareParticipant) {
videoTrack = getVirtualScreenshareParticipantTrack(tracks, id);
} else {
videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id);
}
if (!shouldRenderVideoTrack(videoTrack, /* waitForVideoStarted */ false)) { if (!shouldRenderVideoTrack(videoTrack, /* waitForVideoStarted */ false)) {
return false; return false;

View File

@ -4,6 +4,7 @@ import React, { PureComponent } from 'react';
import { Image, View } from 'react-native'; import { Image, View } from 'react-native';
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
import { getMultipleVideoSupportFeatureFlag } from '../../../base/config';
import { MEDIA_TYPE, VIDEO_TYPE } from '../../../base/media'; import { MEDIA_TYPE, VIDEO_TYPE } from '../../../base/media';
import { import {
PARTICIPANT_ROLE, PARTICIPANT_ROLE,
@ -55,11 +56,21 @@ type Props = {
*/ */
_isFakeParticipant: boolean, _isFakeParticipant: boolean,
/**
* Indicates whether multi-stream support is enabled.
*/
_isMultiStreamSupportEnabled: boolean,
/** /**
* Indicates whether the participant is screen sharing. * Indicates whether the participant is screen sharing.
*/ */
_isScreenShare: boolean, _isScreenShare: boolean,
/**
* Indicates whether the thumbnail is for a virtual screenshare participant.
*/
_isVirtualScreenshare: boolean,
/** /**
* Indicates whether the participant is local. * Indicates whether the participant is local.
*/ */
@ -187,6 +198,7 @@ class Thumbnail extends PureComponent<Props> {
const { const {
_audioMuted: audioMuted, _audioMuted: audioMuted,
_isScreenShare: isScreenShare, _isScreenShare: isScreenShare,
_isVirtualScreenshare,
_isFakeParticipant, _isFakeParticipant,
_renderModeratorIndicator: renderModeratorIndicator, _renderModeratorIndicator: renderModeratorIndicator,
_participantId: participantId, _participantId: participantId,
@ -203,8 +215,8 @@ class Thumbnail extends PureComponent<Props> {
styles.thumbnailTopIndicatorContainer, styles.thumbnailTopIndicatorContainer,
styles.thumbnailTopLeftIndicatorContainer styles.thumbnailTopLeftIndicatorContainer
] }> ] }>
<ConnectionIndicator participantId = { participantId } /> { !_isVirtualScreenshare && <ConnectionIndicator participantId = { participantId } /> }
<RaisedHandIndicator participantId = { participantId } /> { !_isVirtualScreenshare && <RaisedHandIndicator participantId = { participantId } /> }
{tileView && isScreenShare && ( {tileView && isScreenShare && (
<View style = { styles.indicatorContainer }> <View style = { styles.indicatorContainer }>
<ScreenShareIndicator /> <ScreenShareIndicator />
@ -215,10 +227,10 @@ class Thumbnail extends PureComponent<Props> {
key = 'bottom-indicators' key = 'bottom-indicators'
style = { styles.thumbnailIndicatorContainer }> style = { styles.thumbnailIndicatorContainer }>
<Container style = { (audioMuted || renderModeratorIndicator) && styles.bottomIndicatorsContainer }> <Container style = { (audioMuted || renderModeratorIndicator) && styles.bottomIndicatorsContainer }>
{ audioMuted && <AudioMutedIndicator /> } { audioMuted && !_isVirtualScreenshare && <AudioMutedIndicator /> }
{ !tileView && _pinned && <PinnedIndicator />} { !tileView && _pinned && <PinnedIndicator />}
{ renderModeratorIndicator && <ModeratorIndicator />} { renderModeratorIndicator && !_isVirtualScreenshare && <ModeratorIndicator />}
{ !tileView && isScreenShare { !tileView && (isScreenShare || _isVirtualScreenshare)
&& <ScreenShareIndicator /> && <ScreenShareIndicator />
} }
</Container> </Container>
@ -242,8 +254,9 @@ class Thumbnail extends PureComponent<Props> {
render() { render() {
const { const {
_gifSrc, _gifSrc,
_isScreenShare: isScreenShare,
_isFakeParticipant, _isFakeParticipant,
_isScreenShare: isScreenShare,
_isVirtualScreenshare,
_participantId: participantId, _participantId: participantId,
_raisedHand, _raisedHand,
_renderDominantSpeakerIndicator, _renderDominantSpeakerIndicator,
@ -266,8 +279,8 @@ class Thumbnail extends PureComponent<Props> {
style = { [ style = { [
styles.thumbnail, styles.thumbnail,
styleOverrides, styleOverrides,
_raisedHand ? styles.thumbnailRaisedHand : null, _raisedHand && !_isVirtualScreenshare ? styles.thumbnailRaisedHand : null,
_renderDominantSpeakerIndicator ? styles.thumbnailDominantSpeaker : null _renderDominantSpeakerIndicator && !_isVirtualScreenshare ? styles.thumbnailDominantSpeaker : null
] } ] }
touchFeedback = { false }> touchFeedback = { false }>
{_gifSrc ? <Image {_gifSrc ? <Image
@ -303,10 +316,9 @@ function _mapStateToProps(state, ownProps) {
const participant = getParticipantByIdOrUndefined(state, participantID); const participant = getParticipantByIdOrUndefined(state, participantID);
const localParticipantId = getLocalParticipant(state).id; const localParticipantId = getLocalParticipant(state).id;
const id = participant?.id; const id = participant?.id;
const audioTrack const audioTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, id);
= getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, id); const videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id);
const videoTrack const isMultiStreamSupportEnabled = getMultipleVideoSupportFeatureFlag(state);
= getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id);
const isScreenShare = videoTrack?.videoType === VIDEO_TYPE.DESKTOP; const isScreenShare = videoTrack?.videoType === VIDEO_TYPE.DESKTOP;
const participantCount = getParticipantCount(state); const participantCount = getParticipantCount(state);
const renderDominantSpeakerIndicator = participant && participant.dominantSpeaker && participantCount > 2; const renderDominantSpeakerIndicator = participant && participant.dominantSpeaker && participantCount > 2;
@ -320,7 +332,9 @@ function _mapStateToProps(state, ownProps) {
_audioMuted: audioTrack?.muted ?? true, _audioMuted: audioTrack?.muted ?? true,
_gifSrc: mode === 'chat' ? null : gifSrc, _gifSrc: mode === 'chat' ? null : gifSrc,
_isFakeParticipant: participant?.isFakeParticipant, _isFakeParticipant: participant?.isFakeParticipant,
_isMultiStreamSupportEnabled: isMultiStreamSupportEnabled,
_isScreenShare: isScreenShare, _isScreenShare: isScreenShare,
_isVirtualScreenshare: isMultiStreamSupportEnabled && participant?.isVirtualScreenshareParticipant,
_local: participant?.local, _local: participant?.local,
_localVideoOwner: Boolean(ownerId === localParticipantId), _localVideoOwner: Boolean(ownerId === localParticipantId),
_participantId: id, _participantId: id,

View File

@ -108,7 +108,7 @@ function _mapStateToProps(state, ownProps) {
if (participant?.local) { if (participant?.local) {
isAudioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO); isAudioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
} else if (!participant?.isFakeParticipant) { // remote participants excluding shared video } else if (!participant?.isFakeParticipant) { // remote participants excluding shared video
const track = isMultiStreamSupportEnabled const track = isMultiStreamSupportEnabled && participant?.isVirtualScreenshareParticipant
? getVirtualScreenshareParticipantTrack(tracks, participantID) ? getVirtualScreenshareParticipantTrack(tracks, participantID)
: getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantID); : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantID);