diff --git a/app/src/main/java/org/linphone/telecom/TelecomManager.kt b/app/src/main/java/org/linphone/telecom/TelecomManager.kt index f71b43fe8..06d3a99da 100644 --- a/app/src/main/java/org/linphone/telecom/TelecomManager.kt +++ b/app/src/main/java/org/linphone/telecom/TelecomManager.kt @@ -20,6 +20,7 @@ package org.linphone.telecom import android.content.Context +import android.media.AudioManager import androidx.annotation.WorkerThread import androidx.core.telecom.CallAttributesCompat import androidx.core.telecom.CallException @@ -36,6 +37,8 @@ import org.linphone.core.CoreListenerStub import org.linphone.core.tools.Log import org.linphone.utils.LinphoneUtils import androidx.core.net.toUri +import androidx.core.telecom.CallEndpointCompat +import org.linphone.mediastream.Version class TelecomManager @WorkerThread @@ -50,6 +53,10 @@ class TelecomManager private val map = HashMap() + private val communicationDeviceListener = AudioManager.OnCommunicationDeviceChangedListener { device -> + Log.i("$TAG Communication device in use is [$device]") + } + private val coreListener = object : CoreListenerStub() { @WorkerThread override fun onCallStateChanged( @@ -66,9 +73,18 @@ class TelecomManager @WorkerThread override fun onLastCallEnded(core: Core) { currentlyFollowedCalls = 0 + + if (::audioManager.isInitialized) { + if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) { + Log.i("$TAG Last call ended, clearing communication device") + audioManager.clearCommunicationDevice() + } + } } } + private lateinit var audioManager: AudioManager + private var currentlyFollowedCalls: Int = 0 init { @@ -87,6 +103,11 @@ class TelecomManager } catch (e: Exception) { Log.e("$TAG Can't init TelecomManager: $e") } + + audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager + if (::audioManager.isInitialized) { + audioManager.addOnCommunicationDeviceChangedListener(context.mainExecutor, communicationDeviceListener) + } } @WorkerThread @@ -207,6 +228,10 @@ class TelecomManager fun onCoreStopped(core: Core) { Log.i("$TAG Core is being stopped") core.removeListener(coreListener) + + if (::audioManager.isInitialized) { + audioManager.removeOnCommunicationDeviceChangedListener(communicationDeviceListener) + } } @WorkerThread @@ -220,6 +245,46 @@ class TelecomManager return false } - return callControlCallback.applyAudioRouteToCallWithId(routes) + if (Version.sdkStrictlyBelow(Version.API31_ANDROID_12)) { + return callControlCallback.applyAudioRouteToCallWithId(routes) + } else { + val expectedDeviceType = linphoneAudioDeviceTypeToTelecom(routes.first()) + if (expectedDeviceType == CallEndpointCompat.Companion.TYPE_UNKNOWN) { + Log.e("$TAG Requested device type [${routes.first()}] not supported, skipping") + return false + } + + if (::audioManager.isInitialized) { + val currentDevice = audioManager.communicationDevice + Log.i("$TAG Current communication device is [$currentDevice]") + + val devices = audioManager.availableCommunicationDevices + for (device in devices) { + if (device.type == expectedDeviceType) { + Log.i("$TAG Found device matching expected type [$expectedDeviceType]") + val result = audioManager.setCommunicationDevice(device) + if (result) { + Log.i("$TAG Set communication device [$device] successful!") + return true + } else { + Log.i("$TAG Failed to set communication device [$device]!") + return false + } + } + } + } + + return false + } + } + + private fun linphoneAudioDeviceTypeToTelecom(type: AudioDevice.Type): Int { + return when (type) { + AudioDevice.Type.Earpiece -> CallEndpointCompat.Companion.TYPE_EARPIECE + AudioDevice.Type.Bluetooth, AudioDevice.Type.HearingAid -> CallEndpointCompat.Companion.TYPE_BLUETOOTH + AudioDevice.Type.Headphones, AudioDevice.Type.Headset -> CallEndpointCompat.Companion.TYPE_WIRED_HEADSET + AudioDevice.Type.Speaker -> CallEndpointCompat.Companion.TYPE_SPEAKER + else -> CallEndpointCompat.Companion.TYPE_UNKNOWN + } } }