From 7b8cfcf9e2150cf1c4ff3ce710b9e22c873e1113 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Mon, 13 Oct 2025 16:18:05 +1100 Subject: [PATCH 1/2] SES-4529 - Making sure the call tone is attached to the correct audio track --- .../securesms/webrtc/audio/IncomingRinger.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.kt index 1b3995a2aa..d150c653e3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.kt @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.webrtc.audio import android.content.Context +import android.media.AudioAttributes import android.media.AudioManager import android.media.MediaPlayer import android.media.RingtoneManager @@ -76,9 +77,17 @@ class IncomingRinger(private val context: Context) { } ?: return null try { - val mediaPlayer = MediaPlayer() - mediaPlayer.setDataSource(context, defaultRingtone) - return mediaPlayer + return MediaPlayer().apply { + // Make volume follow the "Ring & notification" slider + setAudioAttributes( + AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build() + ) + isLooping = true + setDataSource(context, defaultRingtone) + } } catch (e: SecurityException) { Log.w(TAG, "Failed to create player with ringtone the normal way", e) } From 1fbc626dfc5e920bb9dcdd5e282c98fff2f84713 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Mon, 13 Oct 2025 17:08:16 +1100 Subject: [PATCH 2/2] SES-4668 - Do not locally hangup on self-synced answers If the user has answered from the same account on a different device, we should clean uplocally instead of considering it a local hangup --- .../securesms/webrtc/WebRtcCallBridge.kt | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallBridge.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallBridge.kt index 155e02e6a2..9ed60cbdd5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallBridge.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/WebRtcCallBridge.kt @@ -418,22 +418,28 @@ class WebRtcCallBridge @Inject constructor( fun handleAnswerIncoming(address: Address, sdp: String, callId: UUID) { serviceExecutor.execute { - try { - if (address.isLocalNumber && callManager.currentConnectionState in CallState.CAN_DECLINE_STATES) { - handleLocalHangup(address) - return@execute + val state = callManager.currentConnectionState + val isInitiator = callManager.isInitiator() + + // If we receive a self-synced ANSWER: + if (address.isLocalNumber) { + // Only act if this device was in an INCOMING ring state (answered elsewhere). + if (!isInitiator && state in arrayOf(CallState.RemotePreOffer, CallState.RemoteRing)) { + // Stop ringing / update UI, but DO NOT hang up the remote. + callManager.silenceIncomingRinger() + callManager.handleIgnoreCall() + terminate() + } else { + // We’re the caller or already past ring → ignore self-answer + Log.w(TAG, "Ignoring self-synced ANSWER in state=$state (isInitiator=$isInitiator)") } - - callManager.postViewModelState(CallViewModel.State.CALL_ANSWER_OUTGOING) - - callManager.handleResponseMessage( - address, - callId, - SessionDescription(SessionDescription.Type.ANSWER, sdp) - ) - } catch (e: PeerConnectionException) { - terminate() + return@execute } + + callManager.postViewModelState(CallViewModel.State.CALL_ANSWER_OUTGOING) + callManager.handleResponseMessage( + address, callId, SessionDescription(SessionDescription.Type.ANSWER, sdp) + ) } }