Add additional checks/logs to ringtones

This commit is contained in:
Jamie Kyle 2024-01-04 14:16:33 -08:00 committed by GitHub
parent 93e61a1a3a
commit 422ebf1bc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 102 additions and 32 deletions

View file

@ -73,6 +73,7 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
getPresentingSources: action('get-presenting-sources'),
hangUpActiveCall: action('hang-up-active-call'),
i18n,
incomingCall: null,
isGroupCallRaiseHandEnabled: true,
isGroupCallReactionsEnabled: true,
keyChangeOk: action('key-change-ok'),
@ -189,6 +190,8 @@ export function RingingGroupCall(): JSX.Element {
{...createProps({
incomingCall: {
callMode: CallMode.Group as const,
connectionState: GroupCallConnectionState.NotConnected,
joinState: GroupCallJoinState.NotJoined,
conversation: {
...getConversation(),
type: 'group',
@ -201,6 +204,7 @@ export function RingingGroupCall(): JSX.Element {
{ firstName: 'Summer', title: 'Summer Smith' },
],
ringer: { firstName: 'Rick', title: 'Rick Sanchez' },
remoteParticipants: [],
},
})}
/>

View file

@ -32,6 +32,7 @@ import type {
AcceptCallType,
CancelCallType,
DeclineCallType,
GroupCallParticipantInfoType,
KeyChangeOkType,
SendGroupCallRaiseHandType,
SendGroupCallReactionType,
@ -47,9 +48,28 @@ import { missingCaseError } from '../util/missingCaseError';
import { CallingToastProvider } from './CallingToast';
import type { SmartReactionPicker } from '../state/smart/ReactionPicker';
import type { Props as ReactionPickerProps } from './conversation/ReactionPicker';
import * as log from '../logging/log';
const GROUP_CALL_RING_DURATION = 60 * 1000;
export type DirectIncomingCall = Readonly<{
callMode: CallMode.Direct;
callState?: CallState;
callEndedReason?: CallEndedReason;
conversation: ConversationType;
isVideoCall: boolean;
}>;
export type GroupIncomingCall = Readonly<{
callMode: CallMode.Group;
connectionState: GroupCallConnectionState;
joinState: GroupCallJoinState;
conversation: ConversationType;
otherMembersRung: Array<Pick<ConversationType, 'firstName' | 'title'>>;
ringer: Pick<ConversationType, 'firstName' | 'title'>;
remoteParticipants: Array<GroupCallParticipantInfoType>;
}>;
export type PropsType = {
activeCall?: ActiveCallType;
availableCameras: Array<MediaDeviceInfo>;
@ -62,18 +82,7 @@ export type PropsType = {
) => VideoFrameSource;
getPreferredBadge: PreferredBadgeSelectorType;
getPresentingSources: () => void;
incomingCall?:
| {
callMode: CallMode.Direct;
conversation: ConversationType;
isVideoCall: boolean;
}
| {
callMode: CallMode.Group;
conversation: ConversationType;
otherMembersRung: Array<Pick<ConversationType, 'firstName' | 'title'>>;
ringer: Pick<ConversationType, 'firstName' | 'title'>;
};
incomingCall: DirectIncomingCall | GroupIncomingCall | null;
keyChangeOk: (_: KeyChangeOkType) => void;
renderDeviceSelection: () => JSX.Element;
renderReactionPicker: (
@ -431,8 +440,10 @@ export function CallManager(props: PropsType): JSX.Element | null {
const shouldRing = getShouldRing(props);
useEffect(() => {
if (shouldRing) {
log.info('CallManager: Playing ringtone');
playRingtone();
return () => {
log.info('CallManager: Stopping ringtone');
stopRingtone();
};
}
@ -486,6 +497,31 @@ export function CallManager(props: PropsType): JSX.Element | null {
return null;
}
function isRinging(callState: CallState | undefined): boolean {
return callState === CallState.Prering || callState === CallState.Ringing;
}
function isConnected(connectionState: GroupCallConnectionState): boolean {
return (
connectionState === GroupCallConnectionState.Connecting ||
connectionState === GroupCallConnectionState.Connected
);
}
function isJoined(joinState: GroupCallJoinState): boolean {
return joinState !== GroupCallJoinState.NotJoined;
}
function hasRemoteParticipants(
remoteParticipants: Array<GroupCallParticipantInfoType>
): boolean {
return remoteParticipants.length > 0;
}
function isLonelyGroup(conversation: ConversationType): boolean {
return (conversation.sortedGroupMembers?.length ?? 0) < 2;
}
function getShouldRing({
activeCall,
incomingCall,
@ -493,35 +529,54 @@ function getShouldRing({
}: Readonly<
Pick<PropsType, 'activeCall' | 'incomingCall' | 'isConversationTooBigToRing'>
>): boolean {
if (incomingCall) {
if (incomingCall != null) {
// don't ring a large group
if (isConversationTooBigToRing) {
return false;
}
return !activeCall;
if (activeCall != null) {
return false;
}
if (incomingCall.callMode === CallMode.Direct) {
return (
isRinging(incomingCall.callState) &&
incomingCall.callEndedReason == null
);
}
if (incomingCall.callMode === CallMode.Group) {
return (
!isConnected(incomingCall.connectionState) &&
!isJoined(incomingCall.joinState) &&
!isLonelyGroup(incomingCall.conversation)
);
}
throw missingCaseError(incomingCall);
}
if (!activeCall) {
return false;
}
switch (activeCall.callMode) {
case CallMode.Direct:
if (activeCall != null) {
if (activeCall.callMode === CallMode.Direct) {
return (
activeCall.callState === CallState.Prering ||
activeCall.callState === CallState.Ringing
);
case CallMode.Group:
}
if (activeCall.callMode === CallMode.Group) {
return (
activeCall.outgoingRing &&
(activeCall.connectionState === GroupCallConnectionState.Connecting ||
activeCall.connectionState === GroupCallConnectionState.Connected) &&
activeCall.joinState !== GroupCallJoinState.NotJoined &&
!activeCall.remoteParticipants.length &&
(activeCall.conversation.sortedGroupMembers || []).length >= 2
isConnected(activeCall.connectionState) &&
isJoined(activeCall.joinState) &&
!hasRemoteParticipants(activeCall.remoteParticipants) &&
!isLonelyGroup(activeCall.conversation)
);
default:
throw missingCaseError(activeCall);
}
throw missingCaseError(activeCall);
}
return false;
}

View file

@ -5,6 +5,10 @@ import React from 'react';
import { connect } from 'react-redux';
import { memoize } from 'lodash';
import { mapDispatchToProps } from '../actions';
import type {
DirectIncomingCall,
GroupIncomingCall,
} from '../../components/CallManager';
import { CallManager } from '../../components/CallManager';
import { calling as callingService } from '../../services/calling';
import { getIntl, getTheme } from '../selectors/user';
@ -320,29 +324,33 @@ const mapStateToActiveCallProp = (
}
};
const mapStateToIncomingCallProp = (state: StateType) => {
const mapStateToIncomingCallProp = (
state: StateType
): DirectIncomingCall | GroupIncomingCall | null => {
const call = getIncomingCall(state);
if (!call) {
return undefined;
return null;
}
const conversation = getConversationSelector(state)(call.conversationId);
if (!conversation) {
log.error('The incoming call has no corresponding conversation');
return undefined;
return null;
}
switch (call.callMode) {
case CallMode.Direct:
return {
callMode: CallMode.Direct as const,
callState: call.callState,
callEndedReason: call.callEndedReason,
conversation,
isVideoCall: call.isVideoCall,
};
case CallMode.Group: {
if (!call.ringerAci) {
log.error('The incoming group call has no ring state');
return undefined;
return null;
}
const conversationSelector = getConversationSelector(state);
@ -353,9 +361,12 @@ const mapStateToIncomingCallProp = (state: StateType) => {
return {
callMode: CallMode.Group as const,
connectionState: call.connectionState,
joinState: call.joinState,
conversation,
otherMembersRung,
ringer,
remoteParticipants: call.remoteParticipants,
};
}
default: