From 2771b31aabd63ea0062446564d2dd8513f226261 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 12 Feb 2026 09:18:04 -0400 Subject: [PATCH] Clear stale user-selected audio device when it disconnects. Co-authored-by: Greyson Parrelli --- .../webrtc/audio/FullSignalAudioManagerApi31.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt index 734771c5af..af0e58e51b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt @@ -234,16 +234,25 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener val currentAudioDevice: AudioDeviceInfo? = androidAudioManager.communicationDevice val availableCommunicationDevices: List = androidAudioManager.availableCommunicationDevices + + if (userSelectedAudioDevice != null && availableCommunicationDevices.none { it.id == userSelectedAudioDevice?.id }) { + Log.w(TAG, "User selected device ${userSelectedAudioDevice?.id} of type ${userSelectedAudioDevice?.type?.let { getDeviceTypeName(it) }} is no longer available. Clearing user selection.") + userSelectedAudioDevice = null + } + var candidate: AudioDeviceInfo? = userSelectedAudioDevice if (candidate != null && candidate.id != 0) { val result = androidAudioManager.setCommunicationDevice(candidate) if (result) { eventListener?.onAudioDeviceChanged(AudioDeviceMapping.fromPlatformType(candidate.type), availableCommunicationDevices.map { AudioDeviceMapping.fromPlatformType(it.type) }.toSet()) } else { - Log.w(TAG, "Failed to set ${candidate.id} of type ${getDeviceTypeName(candidate.type)} as communication device.") - eventListener?.onAudioDeviceChangeFailed() + Log.w(TAG, "Failed to set ${candidate.id} of type ${getDeviceTypeName(candidate.type)} as communication device. Clearing user selection.") + userSelectedAudioDevice = null + candidate = null } - } else { + } + + if (candidate == null) { val searchOrder: List = listOf(AudioDevice.BLUETOOTH, AudioDevice.WIRED_HEADSET, defaultAudioDevice, AudioDevice.EARPIECE, AudioDevice.SPEAKER_PHONE, AudioDevice.NONE).distinct() for (deviceType in searchOrder) { candidate = availableCommunicationDevices.filterNot { it.productName.contains(" Watch", true) }.find { AudioDeviceMapping.fromPlatformType(it.type) == deviceType } @@ -256,6 +265,7 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener null -> { Log.e(TAG, "Tried to switch audio devices but could not find suitable device in list of types: ${availableCommunicationDevices.map { getDeviceTypeName(it.type) }.joinToString()}") androidAudioManager.clearCommunicationDevice() + eventListener?.onAudioDeviceChangeFailed() } else -> { Log.d(TAG, "Switching to new device of type ${getDeviceTypeName(candidate.type)} from ${currentAudioDevice?.type?.let { getDeviceTypeName(it) }}")