audio: Let EC decide alone what communication device to use

This commit is contained in:
Valere 2026-04-17 11:52:07 +02:00
parent ae94e0c746
commit 09e57e077a

View file

@ -113,23 +113,7 @@ class WebViewAudioManager(
@get:RequiresApi(Build.VERSION_CODES.S)
private val commsDeviceChangedListener by lazy {
AudioManager.OnCommunicationDeviceChangedListener { device ->
if (device != null && device.id == expectedNewCommunicationDeviceId) {
expectedNewCommunicationDeviceId = null
Timber.d("Audio device changed, type: ${device.type}")
updateSelectedAudioDeviceInWebView(device.id.toString())
} else if (device != null && device.id != expectedNewCommunicationDeviceId) {
// We were expecting a device change but it didn't happen, so we should retry
val expectedDeviceId = expectedNewCommunicationDeviceId
if (expectedDeviceId != null) {
// Remove the expected id so we only retry once
expectedNewCommunicationDeviceId = null
audioManager.selectAudioDevice(expectedDeviceId.toString())
}
} else {
Timber.d("Audio device cleared")
expectedNewCommunicationDeviceId = null
audioManager.selectAudioDevice(null)
}
Timber.d("Audio device changed, type: ${device?.id}")
}
}
@ -144,39 +128,20 @@ class WebViewAudioManager(
// We need to calculate the available devices ourselves, since calling `listAudioDevices` will return an outdated list
val audioDevices = (listAudioDevices() + validNewDevices).distinctBy { it.id }.sortedWith(audioDeviceComparator)
setAvailableAudioDevices(audioDevices.map(SerializableAudioDevice::fromAudioDeviceInfo))
// This should automatically switch to a new device if it has a higher priority than the current one
selectDefaultAudioDevice(audioDevices)
}
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
// Update the available devices
// Element Call will then decide to switch devices if needed
setAvailableAudioDevices()
// Unless the removed device is the current one, we don't need to do anything else
val removedCurrentDevice = removedDevices.orEmpty().any { it.id == currentDeviceId }
if (!removedCurrentDevice) return
val previousDevice = previousSelectedDevice
if (previousDevice != null) {
previousSelectedDevice = null
// If we have a previous device, we should select it again
audioManager.selectAudioDevice(previousDevice.id.toString())
} else {
// If we don't have a previous device, we should select the default one
selectDefaultAudioDevice()
}
}
}
/**
* The currently used audio device id.
*/
private var currentDeviceId: Int? = null
/**
* When a new audio device is selected but not yet set as the communication device by the OS, this id is used to check if the device is the expected one.
*/
private var expectedNewCommunicationDeviceId: Int? = null
//
//
// /**
// * When a new audio device is selected but not yet set as the communication device by the OS, this id is used to check if the device is the expected one.
// */
// private var expectedNewCommunicationDeviceId: Int? = null
/**
* Previously selected device, used to restore the selection when the selected device is removed.
@ -330,23 +295,6 @@ class WebViewAudioManager(
})
}
/**
* Selects the default audio device based on the sorted available devices.
*
* @param availableDevices The list of available audio devices to select from. If not provided, it will use the current list of audio devices.
*/
private fun selectDefaultAudioDevice(availableDevices: List<AudioDeviceInfo> = listAudioDevices()) {
val selectedDevice = availableDevices.firstOrNull()
expectedNewCommunicationDeviceId = selectedDevice?.id
audioManager.selectAudioDevice(selectedDevice)
selectedDevice?.let {
updateSelectedAudioDeviceInWebView(it.id.toString())
} ?: run {
Timber.w("Audio: unable to select default audio device")
}
}
/**
* Updates the WebView's UI to reflect the selected audio device.
*
@ -381,14 +329,14 @@ class WebViewAudioManager(
*
* @param device The info of the audio device to select, or none to clear the selected device.
*/
@Suppress("DEPRECATION")
private fun AudioManager.selectAudioDevice(device: AudioDeviceInfo?) {
currentDeviceId = device?.id
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (device != null) {
runCatchingExceptions {
Timber.d("Setting communication device: ${device.id} - ${deviceName(device.type, device.productName.toString())}")
setCommunicationDevice(device)
if (!setCommunicationDevice(device)) {
Timber.w("Failed to setCommunication device")
}
}.onFailure {
Timber.e(it, "Could not set communication device.")
}
@ -410,16 +358,16 @@ class WebViewAudioManager(
return
}
setAudioEnabled(true)
@Suppress("DEPRECATION")
isSpeakerphoneOn = device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
isBluetoothScoOn = device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO
} else {
@Suppress("DEPRECATION")
isSpeakerphoneOn = false
isBluetoothScoOn = false
}
}
expectedNewCommunicationDeviceId = null
coroutineScope.launch {
proximitySensorMutex.withLock {
@Suppress("WakeLock", "WakeLockTimeout")