Show local speaking indicator for group calls

This commit is contained in:
Evan Hahn 2022-02-25 09:24:05 -06:00 committed by GitHub
parent dbb732e7cf
commit 41b4cce6ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 87 additions and 32 deletions

View file

@ -15,6 +15,7 @@ import { getPlatform } from '../selectors/user';
import { isConversationTooBigToRing } from '../../conversations/isConversationTooBigToRing';
import { missingCaseError } from '../../util/missingCaseError';
import { calling } from '../../services/calling';
import { AUDIO_LEVEL_FOR_SPEAKING } from '../../calling/constants';
import type { StateType as RootStateType } from '../reducer';
import type {
ChangeIODevicePayloadType,
@ -102,6 +103,7 @@ export type ActiveCallStateType = {
conversationId: string;
hasLocalAudio: boolean;
hasLocalVideo: boolean;
amISpeaking: boolean;
isInSpeakerView: boolean;
joinedAt?: number;
outgoingRing: boolean;
@ -463,6 +465,7 @@ type DeclineCallActionType = {
type GroupCallAudioLevelsChangeActionPayloadType = Readonly<{
conversationId: string;
localAudioLevel: number;
remoteDeviceStates: ReadonlyArray<{ audioLevel: number; demuxId: number }>;
}>;
@ -1431,6 +1434,7 @@ export function reducer(
conversationId: action.payload.conversationId,
hasLocalAudio: action.payload.hasLocalAudio,
hasLocalVideo: action.payload.hasLocalVideo,
amISpeaking: false,
isInSpeakerView: false,
pip: false,
safetyNumberChangedUuids: [],
@ -1458,6 +1462,7 @@ export function reducer(
conversationId: action.payload.conversationId,
hasLocalAudio: action.payload.hasLocalAudio,
hasLocalVideo: action.payload.hasLocalVideo,
amISpeaking: false,
isInSpeakerView: false,
pip: false,
safetyNumberChangedUuids: [],
@ -1480,6 +1485,7 @@ export function reducer(
conversationId: action.payload.conversationId,
hasLocalAudio: true,
hasLocalVideo: action.payload.asVideoCall,
amISpeaking: false,
isInSpeakerView: false,
pip: false,
safetyNumberChangedUuids: [],
@ -1633,6 +1639,7 @@ export function reducer(
conversationId: action.payload.conversationId,
hasLocalAudio: action.payload.hasLocalAudio,
hasLocalVideo: action.payload.hasLocalVideo,
amISpeaking: false,
isInSpeakerView: false,
pip: false,
safetyNumberChangedUuids: [],
@ -1690,24 +1697,36 @@ export function reducer(
}
if (action.type === GROUP_CALL_AUDIO_LEVELS_CHANGE) {
const { conversationId, remoteDeviceStates } = action.payload;
const { conversationId, localAudioLevel, remoteDeviceStates } =
action.payload;
const { activeCallState } = state;
const existingCall = getGroupCall(conversationId, state);
if (!existingCall) {
// The PiP check is an optimization. We don't need to update audio levels if the user
// cannot see them.
if (!activeCallState || activeCallState.pip || !existingCall) {
return state;
}
const amISpeaking = localAudioLevel > AUDIO_LEVEL_FOR_SPEAKING;
const speakingDemuxIds = new Set<number>();
remoteDeviceStates.forEach(({ audioLevel, demuxId }) => {
// We expect `audioLevel` to be a number but have this check just in case.
if (typeof audioLevel === 'number' && audioLevel > 0.25) {
if (
typeof audioLevel === 'number' &&
audioLevel > AUDIO_LEVEL_FOR_SPEAKING
) {
speakingDemuxIds.add(demuxId);
}
});
// This action is dispatched frequently. This equality check helps avoid re-renders.
const oldAmISpeaking = activeCallState.amISpeaking;
const oldSpeakingDemuxIds = existingCall.speakingDemuxIds;
if (
oldAmISpeaking === amISpeaking &&
oldSpeakingDemuxIds &&
setUtil.isEqual(oldSpeakingDemuxIds, speakingDemuxIds)
) {
@ -1716,6 +1735,7 @@ export function reducer(
return {
...state,
activeCallState: { ...activeCallState, amISpeaking },
callsByConversation: {
...callsByConversation,
[conversationId]: { ...existingCall, speakingDemuxIds },