Add screensharing behind a feature flag

This commit is contained in:
Josh Perez 2021-05-20 17:54:03 -04:00 committed by Scott Nonnenberg
parent 7c7f7ee5a0
commit ceffc2380c
49 changed files with 2044 additions and 164 deletions

View file

@ -21,18 +21,23 @@ import {
CallState,
GroupCallConnectionState,
GroupCallVideoRequest,
PresentedSource,
VideoFrameSource,
} from '../types/Calling';
import { CallingToastManager } from './CallingToastManager';
import { ColorType } from '../types/Colors';
import { LocalizerType } from '../types/Util';
import { missingCaseError } from '../util/missingCaseError';
import { DirectCallRemoteParticipant } from './DirectCallRemoteParticipant';
import { GroupCallRemoteParticipants } from './GroupCallRemoteParticipants';
import { GroupCallToastManager } from './GroupCallToastManager';
import { LocalizerType } from '../types/Util';
import { isScreenSharingEnabled } from '../util/isScreenSharingEnabled';
import { missingCaseError } from '../util/missingCaseError';
import { useActivateSpeakerViewOnPresenting } from '../hooks/useActivateSpeakerViewOnPresenting';
import { NeedsScreenRecordingPermissionsModal } from './NeedsScreenRecordingPermissionsModal';
export type PropsType = {
activeCall: ActiveCallType;
getGroupCallVideoFrameSource: (demuxId: number) => VideoFrameSource;
getPresentingSources: () => void;
hangUp: (_: HangUpType) => void;
i18n: LocalizerType;
joinedAt?: number;
@ -44,14 +49,17 @@ export type PropsType = {
profileName?: string;
title: string;
};
openSystemPreferencesAction: () => unknown;
setGroupCallVideoRequest: (_: Array<GroupCallVideoRequest>) => void;
setLocalAudio: (_: SetLocalAudioType) => void;
setLocalVideo: (_: SetLocalVideoType) => void;
setLocalPreview: (_: SetLocalPreviewType) => void;
setPresenting: (_?: PresentedSource) => void;
setRendererCanvas: (_: SetRendererCanvasType) => void;
stickyControls: boolean;
toggleParticipants: () => void;
togglePip: () => void;
toggleScreenRecordingPermissionsDialog: () => unknown;
toggleSettings: () => void;
toggleSpeakerView: () => void;
};
@ -59,18 +67,22 @@ export type PropsType = {
export const CallScreen: React.FC<PropsType> = ({
activeCall,
getGroupCallVideoFrameSource,
getPresentingSources,
hangUp,
i18n,
joinedAt,
me,
openSystemPreferencesAction,
setGroupCallVideoRequest,
setLocalAudio,
setLocalVideo,
setLocalPreview,
setPresenting,
setRendererCanvas,
stickyControls,
toggleParticipants,
togglePip,
toggleScreenRecordingPermissionsDialog,
toggleSettings,
toggleSpeakerView,
}) => {
@ -78,9 +90,19 @@ export const CallScreen: React.FC<PropsType> = ({
conversation,
hasLocalAudio,
hasLocalVideo,
isInSpeakerView,
presentingSource,
remoteParticipants,
showNeedsScreenRecordingPermissionsWarning,
showParticipantsList,
} = activeCall;
useActivateSpeakerViewOnPresenting(
remoteParticipants,
isInSpeakerView,
toggleSpeakerView
);
const toggleAudio = useCallback(() => {
setLocalAudio({
enabled: !hasLocalAudio,
@ -93,6 +115,14 @@ export const CallScreen: React.FC<PropsType> = ({
});
}, [setLocalVideo, hasLocalVideo]);
const togglePresenting = useCallback(() => {
if (presentingSource) {
setPresenting();
} else {
getPresentingSources();
}
}, [getPresentingSources, presentingSource, setPresenting]);
const [acceptedDuration, setAcceptedDuration] = useState<number | null>(null);
const [showControls, setShowControls] = useState(true);
@ -151,7 +181,11 @@ export const CallScreen: React.FC<PropsType> = ({
};
}, [toggleAudio, toggleVideo]);
const hasRemoteVideo = activeCall.remoteParticipants.some(
const currentPresenter = remoteParticipants.find(
participant => participant.presenting
);
const hasRemoteVideo = remoteParticipants.some(
remoteParticipant => remoteParticipant.hasRemoteVideo
);
@ -183,16 +217,22 @@ export const CallScreen: React.FC<PropsType> = ({
case CallMode.Group:
participantCount = activeCall.remoteParticipants.length + 1;
headerMessage = undefined;
headerTitle = activeCall.remoteParticipants.length
? undefined
: i18n('calling__in-this-call--zero');
if (currentPresenter) {
headerTitle = i18n('calling__presenting--person-ongoing', [
currentPresenter.title,
]);
} else if (!activeCall.remoteParticipants.length) {
headerTitle = i18n('calling__in-this-call--zero');
}
isConnected =
activeCall.connectionState === GroupCallConnectionState.Connected;
remoteParticipantsElement = (
<GroupCallRemoteParticipants
getGroupCallVideoFrameSource={getGroupCallVideoFrameSource}
i18n={i18n}
isInSpeakerView={activeCall.isInSpeakerView}
isInSpeakerView={isInSpeakerView}
remoteParticipants={activeCall.remoteParticipants}
setGroupCallVideoRequest={setGroupCallVideoRequest}
/>
@ -206,9 +246,15 @@ export const CallScreen: React.FC<PropsType> = ({
activeCall.callMode === CallMode.Group &&
!activeCall.remoteParticipants.length;
const videoButtonType = hasLocalVideo
? CallingButtonType.VIDEO_ON
: CallingButtonType.VIDEO_OFF;
let videoButtonType: CallingButtonType;
if (presentingSource) {
videoButtonType = CallingButtonType.VIDEO_DISABLED;
} else if (hasLocalVideo) {
videoButtonType = CallingButtonType.VIDEO_ON;
} else {
videoButtonType = CallingButtonType.VIDEO_OFF;
}
const audioButtonType = hasLocalAudio
? CallingButtonType.AUDIO_ON
: CallingButtonType.AUDIO_OFF;
@ -222,6 +268,23 @@ export const CallScreen: React.FC<PropsType> = ({
!showControls && !isAudioOnly && isConnected,
});
const isGroupCall = activeCall.callMode === CallMode.Group;
const localPreviewVideoClass = classNames({
'module-ongoing-call__footer__local-preview__video': true,
'module-ongoing-call__footer__local-preview__video--presenting': Boolean(
presentingSource
),
});
let presentingButtonType: CallingButtonType;
if (presentingSource) {
presentingButtonType = CallingButtonType.PRESENTING_ON;
} else if (currentPresenter) {
presentingButtonType = CallingButtonType.PRESENTING_DISABLED;
} else {
presentingButtonType = CallingButtonType.PRESENTING_OFF;
}
return (
<div
className={classNames(
@ -235,20 +298,24 @@ export const CallScreen: React.FC<PropsType> = ({
}}
role="group"
>
{activeCall.callMode === CallMode.Group ? (
<GroupCallToastManager
connectionState={activeCall.connectionState}
{showNeedsScreenRecordingPermissionsWarning ? (
<NeedsScreenRecordingPermissionsModal
toggleScreenRecordingPermissionsDialog={
toggleScreenRecordingPermissionsDialog
}
i18n={i18n}
openSystemPreferencesAction={openSystemPreferencesAction}
/>
) : null}
<CallingToastManager activeCall={activeCall} i18n={i18n} />
<div
className={classNames('module-ongoing-call__header', controlsFadeClass)}
>
<CallingHeader
canPip
i18n={i18n}
isInSpeakerView={activeCall.isInSpeakerView}
isGroupCall={activeCall.callMode === CallMode.Group}
isInSpeakerView={isInSpeakerView}
isGroupCall={isGroupCall}
message={headerMessage}
participantCount={participantCount}
showParticipantsList={showParticipantsList}
@ -263,7 +330,7 @@ export const CallScreen: React.FC<PropsType> = ({
{hasLocalVideo && isLonelyInGroup ? (
<div className="module-ongoing-call__local-preview-fullsize">
<video
className="module-ongoing-call__footer__local-preview__video"
className={localPreviewVideoClass}
ref={localVideoRef}
autoPlay
/>
@ -308,6 +375,13 @@ export const CallScreen: React.FC<PropsType> = ({
controlsFadeClass
)}
>
{isScreenSharingEnabled() ? (
<CallingButton
buttonType={presentingButtonType}
i18n={i18n}
onClick={togglePresenting}
/>
) : null}
<CallingButton
buttonType={videoButtonType}
i18n={i18n}
@ -333,7 +407,7 @@ export const CallScreen: React.FC<PropsType> = ({
>
{hasLocalVideo && !isLonelyInGroup ? (
<video
className="module-ongoing-call__footer__local-preview__video"
className={localPreviewVideoClass}
ref={localVideoRef}
autoPlay
/>