In call link lobby mute audio by default when peeking many devices

This commit is contained in:
ayumi-signal 2024-09-10 14:26:34 -07:00 committed by GitHub
parent 1037fab680
commit c901f47dd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 137 additions and 16 deletions

View file

@ -76,7 +76,11 @@ import { ToastType } from '../../types/Toast';
import type { ShowToastActionType } from './toast';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions';
import { isAnybodyElseInGroupCall } from './callingHelpers';
import {
isAnybodyElseInGroupCall,
isAnybodyInGroupCall,
MAX_CALL_PARTICIPANTS_FOR_DEFAULT_MUTE,
} from './callingHelpers';
import { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
import {
isGroupOrAdhocCallMode,
@ -2215,7 +2219,8 @@ const _startCallLinkLobby = async ({
const callLobbyData = await calling.startCallLinkLobby({
callLinkRootKey,
adminPasskey,
hasLocalAudio: groupCallDeviceCount < 8,
hasLocalAudio:
groupCallDeviceCount < MAX_CALL_PARTICIPANTS_FOR_DEFAULT_MUTE,
});
if (!callLobbyData) {
return;
@ -2314,7 +2319,8 @@ function startCallingLobby({
const callLobbyData = await calling.startCallingLobby({
conversation,
hasLocalAudio: groupCallDeviceCount < 8,
hasLocalAudio:
groupCallDeviceCount < MAX_CALL_PARTICIPANTS_FOR_DEFAULT_MUTE,
hasLocalVideo: isVideoCall,
});
if (!callLobbyData) {
@ -3114,6 +3120,17 @@ export function reducer(
hasLocalAudio,
hasLocalVideo,
};
// The first time we detect call participants in the lobby, check participant count
// and mute ourselves if over the threshold.
if (
joinState === GroupCallJoinState.NotJoined &&
!isAnybodyInGroupCall(existingCall?.peekInfo) &&
newPeekInfo.deviceCount >= MAX_CALL_PARTICIPANTS_FOR_DEFAULT_MUTE &&
newActiveCallState?.hasLocalAudio
) {
newActiveCallState.hasLocalAudio = false;
}
} else {
newActiveCallState = state.activeCallState;
}

View file

@ -14,6 +14,8 @@ import type {
GroupCallStateType,
} from './calling';
export const MAX_CALL_PARTICIPANTS_FOR_DEFAULT_MUTE = 8;
// In theory, there could be multiple incoming calls, or an incoming call while there's
// an active call. In practice, the UI is not ready for this, and RingRTC doesn't
// support it for direct calls.

View file

@ -137,6 +137,28 @@ describe('calling duck', () => {
},
};
const stateWithNotJoinedGroupCall: CallingStateType = {
...getEmptyState(),
callsByConversation: {
'fake-group-call-conversation-id': {
callMode: CallMode.Group,
conversationId: 'fake-group-call-conversation-id',
connectionState: GroupCallConnectionState.NotConnected,
joinState: GroupCallJoinState.NotJoined,
localDemuxId: 1,
peekInfo: {
acis: [],
pendingAcis: [],
creatorAci,
eraId: 'xyz',
maxDevices: 16,
deviceCount: 0,
},
remoteParticipants: [],
} satisfies GroupCallStateType,
},
};
const stateWithIncomingGroupCall: CallingStateType = {
...stateWithGroupCall,
callsByConversation: {
@ -151,21 +173,23 @@ describe('calling duck', () => {
},
};
const groupCallActiveCallState: ActiveCallStateType = {
callMode: CallMode.Group,
conversationId: 'fake-group-call-conversation-id',
hasLocalAudio: true,
hasLocalVideo: false,
localAudioLevel: 0,
viewMode: CallViewMode.Paginated,
showParticipantsList: false,
outgoingRing: false,
pip: false,
settingsDialogOpen: false,
joinedAt: null,
};
const stateWithActiveGroupCall: CallingStateTypeWithActiveCall = {
...stateWithGroupCall,
activeCallState: {
callMode: CallMode.Group,
conversationId: 'fake-group-call-conversation-id',
hasLocalAudio: true,
hasLocalVideo: false,
localAudioLevel: 0,
viewMode: CallViewMode.Paginated,
showParticipantsList: false,
outgoingRing: false,
pip: false,
settingsDialogOpen: false,
joinedAt: null,
},
activeCallState: groupCallActiveCallState,
};
const ourAci = generateAci();
@ -1319,6 +1343,84 @@ describe('calling duck', () => {
assert.isFalse(result.activeCallState?.outgoingRing);
});
it('mutes self in lobby when getting peek info with a lot of devices', () => {
const result = reducer(
{
...stateWithNotJoinedGroupCall,
activeCallState: groupCallActiveCallState,
},
getAction({
callMode: CallMode.Group,
conversationId: 'fake-group-call-conversation-id',
connectionState: GroupCallConnectionState.Connecting,
joinState: GroupCallJoinState.NotJoined,
localDemuxId: 1,
hasLocalAudio: true,
hasLocalVideo: true,
peekInfo: {
acis: Array(20).map(generateAci),
pendingAcis: [],
maxDevices: 16,
deviceCount: 20,
},
remoteParticipants: [],
})
);
assert.isFalse(result.activeCallState?.hasLocalAudio);
});
it('does not mute self when getting peek info with few devices', () => {
const result = reducer(
{
...stateWithNotJoinedGroupCall,
activeCallState: groupCallActiveCallState,
},
getAction({
callMode: CallMode.Group,
conversationId: 'fake-group-call-conversation-id',
connectionState: GroupCallConnectionState.Connecting,
joinState: GroupCallJoinState.NotJoined,
localDemuxId: 1,
hasLocalAudio: true,
hasLocalVideo: true,
peekInfo: {
acis: [ACI_1],
pendingAcis: [],
maxDevices: 16,
deviceCount: 1,
},
remoteParticipants: [],
})
);
assert.isTrue(result.activeCallState?.hasLocalAudio);
});
it('does not mute self when connected with many devices', () => {
const result = reducer(
stateWithActiveGroupCall,
getAction({
callMode: CallMode.Group,
conversationId: 'fake-group-call-conversation-id',
connectionState: GroupCallConnectionState.Connected,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
hasLocalAudio: true,
hasLocalVideo: true,
peekInfo: {
acis: Array(20).map(generateAci),
pendingAcis: [],
maxDevices: 16,
deviceCount: 20,
},
remoteParticipants: [],
})
);
assert.isTrue(result.activeCallState?.hasLocalAudio);
});
});
describe('handleCallLinkUpdate', () => {