From 60fa6a11eff9cad863baec1f0917e636d71ac639 Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:40:37 -0700 Subject: [PATCH] Better group call state management --- ts/services/calling.ts | 21 +++++++++------- ts/state/ducks/calling.ts | 41 +++++++++++++++++++++++++++----- ts/textsecure/MessageReceiver.ts | 7 ++++-- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/ts/services/calling.ts b/ts/services/calling.ts index 80833d25ce..f64af71909 100644 --- a/ts/services/calling.ts +++ b/ts/services/calling.ts @@ -1925,19 +1925,19 @@ export class CallingClass { envelope: ProcessedEnvelope, callingMessage: Proto.ICallingMessage ): Promise { - log.info('CallingClass.handleCallingMessage()'); + const logId = `CallingClass.handleCallingMessage(${envelope.timestamp})`; const enableIncomingCalls = window.Events.getIncomingCallNotification(); if (callingMessage.offer && !enableIncomingCalls) { // Drop offers silently if incoming call notifications are disabled. - log.info('Incoming calls are disabled, ignoring call offer.'); + log.info(`${logId}: Incoming calls are disabled, ignoring call offer.`); return; } const remoteUserId = envelope.sourceServiceId; const remoteDeviceId = this.parseDeviceId(envelope.sourceDevice); if (!remoteUserId || !remoteDeviceId || !this.localDeviceId) { - log.error('Missing identifier, ignoring call message.'); + log.error(`${logId}: Missing identifier, ignoring call message.`); return; } @@ -1946,7 +1946,9 @@ export class CallingClass { const senderIdentityRecord = await storage.protocol.getOrMigrateIdentityRecord(remoteUserId); if (!senderIdentityRecord) { - log.error('Missing sender identity record; ignoring call message.'); + log.error( + `${logId}: Missing sender identity record; ignoring call message.` + ); return; } const senderIdentityKey = senderIdentityRecord.publicKey.slice(1); // Ignore the type header, it is not used. @@ -1955,14 +1957,16 @@ export class CallingClass { const receiverIdentityRecord = storage.protocol.getIdentityRecord(ourAci); if (!receiverIdentityRecord) { - log.error('Missing receiver identity record; ignoring call message.'); + log.error( + `${logId}: Missing receiver identity record; ignoring call message.` + ); return; } const receiverIdentityKey = receiverIdentityRecord.publicKey.slice(1); // Ignore the type header, it is not used. const conversation = window.ConversationController.get(remoteUserId); if (!conversation) { - log.error('Missing conversation; ignoring call message.'); + log.error(`${logId}: Missing conversation; ignoring call message.`); return; } @@ -1971,7 +1975,8 @@ export class CallingClass { !conversation.getAccepted({ ignoreEmptyConvo: true }) ) { log.info( - 'Conversation was not approved by user; rejecting call message.' + `${logId}: Conversation was not approved by user; ` + + 'rejecting call message.' ); const { callId } = callingMessage.offer; @@ -2020,7 +2025,7 @@ export class CallingClass { const messageAgeSec = envelope.messageAgeSec ? envelope.messageAgeSec : 0; - log.info('CallingClass.handleCallingMessage(): Handling in RingRTC'); + log.info(`${logId}: Handling in RingRTC`); RingRTC.handleCallingMessage( remoteUserId, diff --git a/ts/state/ducks/calling.ts b/ts/state/ducks/calling.ts index 1f97d43d2d..8ea508a4a2 100644 --- a/ts/state/ducks/calling.ts +++ b/ts/state/ducks/calling.ts @@ -1198,12 +1198,6 @@ function groupCallStateChange( const { ourAci } = getState().user; strictAssert(ourAci, 'groupCallStateChange failed to fetch our ACI'); - log.info( - 'groupCallStateChange:', - payload.conversationId, - GroupCallConnectionState[payload.connectionState], - GroupCallJoinState[payload.joinState] - ); dispatch({ type: GROUP_CALL_STATE_CHANGE, payload: { @@ -2564,6 +2558,41 @@ export function reducer( const existingCall = getGroupCall(conversationId, state, callMode); const existingRingState = getGroupCallRingState(existingCall); + // Generare a better log line that would help piece together ACIs and + // demuxIds. + const currentlyInCall = new Map( + existingCall?.remoteParticipants.map(({ demuxId, aci }) => [ + demuxId, + aci, + ]) ?? [] + ); + const nextInCall = new Map( + remoteParticipants.map(({ demuxId, aci }) => [demuxId, aci]) ?? [] + ); + + const membersLeft = new Array<`${AciString}:${number}`>(); + for (const [demuxId, aci] of currentlyInCall) { + if (!nextInCall.has(demuxId)) { + membersLeft.push(`${aci}:${demuxId}`); + } + } + + const membersJoined = new Array<`${AciString}:${number}`>(); + for (const [demuxId, aci] of nextInCall) { + if (!currentlyInCall.has(demuxId)) { + membersJoined.push(`${aci}:${demuxId}`); + } + } + + log.info( + 'groupCallStateChange:', + conversationId, + GroupCallConnectionState[connectionState], + GroupCallJoinState[joinState], + `joined={${membersJoined.join(', ')}}`, + `left={${membersLeft.join(', ')}}` + ); + const newPeekInfo = peekInfo || existingCall?.peekInfo || { acis: remoteParticipants.map(({ aci }) => aci), diff --git a/ts/textsecure/MessageReceiver.ts b/ts/textsecure/MessageReceiver.ts index 0adf507466..912528bf68 100644 --- a/ts/textsecure/MessageReceiver.ts +++ b/ts/textsecure/MessageReceiver.ts @@ -2807,18 +2807,21 @@ export default class MessageReceiver this.removeFromCache(envelope); + const logId = `MessageReceiver.handleCallingMessage(${getEnvelopeId( + envelope + )})`; + if ( (envelope.source && this.isBlocked(envelope.source)) || (envelope.sourceServiceId && this.isServiceIdBlocked(envelope.sourceServiceId)) ) { - const logId = getEnvelopeId(envelope); - log.info(`${logId}: Dropping calling message from blocked sender`); this.removeFromCache(envelope); return; } + log.info(`${logId}: Passing to ringrtc`); await window.Signal.Services.calling.handleCallingMessage( envelope, callingMessage