From 6486a0a995eeb4de6084ce295c51da39865e1979 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 6 Apr 2026 19:29:36 +0000 Subject: [PATCH] fix: stop ringing immediately when caller cancels WebRTC call Move transitionToEnded() before the signing + relay publish in hangup() so the UI stops ringing/ringback immediately, matching the pattern already used by rejectCall(). Add onDestroy safety net in CallActivity to hang up if the Activity is destroyed while a call is active. Wrap audio stop methods in try-catch to prevent one failure from blocking the others. https://claude.ai/code/session_01Rip2HPCbF48PPFDiB2X5ik --- .../amethyst/service/call/CallAudioManager.kt | 17 ++++++++++++---- .../amethyst/ui/call/CallActivity.kt | 20 +++++++++++++++++++ .../amethyst/commons/call/CallManager.kt | 5 ++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallAudioManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallAudioManager.kt index cae4dde30e..8048c298c3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallAudioManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallAudioManager.kt @@ -118,8 +118,11 @@ class CallAudioManager( } fun stopRingbackTone() { - ringbackTone?.stopTone() - ringbackTone?.release() + try { + ringbackTone?.stopTone() + ringbackTone?.release() + } catch (_: Exception) { + } ringbackTone = null } @@ -355,7 +358,10 @@ class CallAudioManager( } private fun stopRingtone() { - ringtone?.stop() + try { + ringtone?.stop() + } catch (_: Exception) { + } ringtone = null } @@ -376,7 +382,10 @@ class CallAudioManager( } private fun stopVibration() { - vibrator?.cancel() + try { + vibrator?.cancel() + } catch (_: Exception) { + } vibrator = null } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt index a82a2ce6de..0d9b8ebe66 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt @@ -207,8 +207,28 @@ class CallActivity : AppCompatActivity() { } } + @OptIn(DelicateCoroutinesApi::class) override fun onDestroy() { unregisterPipReceiver() + + // Safety net: if the Activity is destroyed while a call is still + // ringing/offering, ensure the call is hung up so audio stops. + val manager = ActiveCallHolder.callManager + when (manager?.state?.value) { + is CallState.IncomingCall -> { + GlobalScope.launch { manager.rejectCall() } + } + + is CallState.Offering, + is CallState.Connecting, + is CallState.Connected, + -> { + GlobalScope.launch { manager.hangup() } + } + + else -> {} + } + super.onDestroy() } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/call/CallManager.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/call/CallManager.kt index f5493923b6..2ff076835a 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/call/CallManager.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/call/CallManager.kt @@ -505,9 +505,12 @@ class CallManager( } } + // Transition immediately so the UI stops ringing/ringback before + // the (potentially slow) signing + relay publish completes. + transitionToEnded(callId, peerPubKeys, EndReason.HANGUP) + val result = factory.createGroupHangup(peerPubKeys, callId, signer = signer) result.wraps.forEach { publishEvent(it) } - transitionToEnded(callId, peerPubKeys, EndReason.HANGUP) } fun onPeerHangup(event: CallHangupEvent) {