Skip to content

Commit acdf636

Browse files
committed
Try routing audio to external device
1 parent b570a0b commit acdf636

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

features/call/impl/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ dependencies {
7575
implementation(projects.appconfig)
7676
implementation(projects.features.enterprise.api)
7777
implementation(projects.libraries.architecture)
78+
implementation(projects.libraries.androidutils)
7879
implementation(projects.libraries.core)
7980
implementation(projects.libraries.designsystem)
8081
implementation(projects.libraries.featureflag.api)

features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import io.element.android.features.call.impl.pip.PictureInPictureStateProvider
3737
import io.element.android.features.call.impl.pip.aPictureInPictureState
3838
import io.element.android.features.call.impl.utils.WebViewPipController
3939
import io.element.android.features.call.impl.utils.WebViewWidgetMessageInterceptor
40+
import io.element.android.libraries.androidutils.compat.disableExternalAudioDevice
41+
import io.element.android.libraries.androidutils.compat.enableExternalAudioDevice
4042
import io.element.android.libraries.architecture.AsyncData
4143
import io.element.android.libraries.designsystem.components.ProgressDialog
4244
import io.element.android.libraries.designsystem.components.button.BackButton
@@ -155,6 +157,8 @@ private fun CallWebView(
155157
// Set 'voice call' mode so volume keys actually control the call volume
156158
val audioManager = context.getSystemService<AudioManager>()
157159
audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION
160+
161+
audioManager?.enableExternalAudioDevice()
158162

159163
WebView(context).apply {
160164
onWebViewCreate(this)
@@ -169,6 +173,7 @@ private fun CallWebView(
169173
onRelease = { webView ->
170174
// Reset audio mode
171175
val audioManager = webView.context.getSystemService<AudioManager>()
176+
audioManager?.disableExternalAudioDevice()
172177
audioManager?.mode = AudioManager.MODE_NORMAL
173178

174179
webView.destroy()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
package io.element.android.libraries.androidutils.compat
9+
10+
import android.media.AudioDeviceInfo
11+
import android.media.AudioManager
12+
import android.os.Build
13+
14+
fun AudioManager.enableExternalAudioDevice() {
15+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
16+
// The list of device types that are considered as communication devices, sorted by likelihood of it being used for communication.
17+
val wantedDeviceTypes = listOf(
18+
// Paired bluetooth device with microphone
19+
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
20+
// USB devices which can play or record audio
21+
AudioDeviceInfo.TYPE_USB_HEADSET,
22+
AudioDeviceInfo.TYPE_USB_DEVICE,
23+
AudioDeviceInfo.TYPE_USB_ACCESSORY,
24+
// Wired audio devices
25+
AudioDeviceInfo.TYPE_WIRED_HEADSET,
26+
AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
27+
// The built-in earpiece of the device
28+
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
29+
// The built-in speaker of the device
30+
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
31+
)
32+
val devices = availableCommunicationDevices
33+
val selectedDevice = devices.find {
34+
wantedDeviceTypes.contains(it.type)
35+
}
36+
selectedDevice?.let { setCommunicationDevice(it) }
37+
} else {
38+
isSpeakerphoneOn = true
39+
}
40+
}
41+
42+
fun AudioManager.disableExternalAudioDevice() {
43+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
44+
clearCommunicationDevice()
45+
} else {
46+
isSpeakerphoneOn = false
47+
}
48+
}

0 commit comments

Comments
 (0)