Route audio to headset/headphones if available (replaces earpiece)

This commit is contained in:
Sylvain Berfini 2021-04-23 14:31:41 +02:00
parent 5d2621af03
commit f78be7e306
4 changed files with 50 additions and 18 deletions

View file

@ -39,6 +39,7 @@ This version is a full rewrite of the app in kotlin, using modern Android compon
- Call history view groups call from the same SIP URI (like linphone-iphone)
- Reworked conference (using new linphone-sdk APIs)
- Route audio to headset / headphones / bluetooth device automatically when available
- Improved how Android native contacts are used
- Switched to material design for text input fields & switches
- Launcher shortcuts can be to either contacts or chat rooms

View file

@ -195,9 +195,13 @@ class ControlsViewModel : ViewModel() {
val wasBluetoothPreviouslyAvailable = audioRoutesEnabled.value == true
updateAudioRoutesState()
if (!wasBluetoothPreviouslyAvailable && corePreferences.routeAudioToBluetoothIfAvailable) {
if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) {
AudioRouteUtils.routeAudioToHeadset()
} else if (!wasBluetoothPreviouslyAvailable && corePreferences.routeAudioToBluetoothIfAvailable) {
// Only attempt to route audio to bluetooth automatically when bluetooth device is connected
AudioRouteUtils.routeAudioToBluetooth()
if (AudioRouteUtils.isBluetoothAudioRouteAvailable()) {
AudioRouteUtils.routeAudioToBluetooth()
}
}
}
}
@ -375,7 +379,12 @@ class ControlsViewModel : ViewModel() {
fun forceEarpieceAudioRoute() {
somethingClickedEvent.value = Event(true)
AudioRouteUtils.routeAudioToEarpiece()
if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) {
Log.i("[Call] Headset found, route audio to it instead of earpiece")
AudioRouteUtils.routeAudioToHeadset()
} else {
AudioRouteUtils.routeAudioToEarpiece()
}
}
fun forceSpeakerAudioRoute() {

View file

@ -194,9 +194,14 @@ class CoreContext(val context: Context, coreConfig: Config) {
} else if (state == Call.State.StreamsRunning) {
// Do not automatically route audio to bluetooth after first call
if (core.callsNb == 1) {
// Only try to route bluetooth when the call is in StreamsRunning for the first time
if (previousCallState == Call.State.Connected && corePreferences.routeAudioToBluetoothIfAvailable) {
AudioRouteUtils.routeAudioToBluetooth(call)
// Only try to route bluetooth / headphone / headset when the call is in StreamsRunning for the first time
if (previousCallState == Call.State.Connected) {
Log.i("[Context] First call going into StreamsRunning state for the first time, trying to route audio to headset or bluetooth if available")
if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) {
AudioRouteUtils.routeAudioToHeadset(call)
} else if (corePreferences.routeAudioToBluetoothIfAvailable && AudioRouteUtils.isBluetoothAudioRouteAvailable()) {
AudioRouteUtils.routeAudioToBluetooth(call)
}
}
}

View file

@ -68,18 +68,36 @@ class AudioRouteUtils {
val currentCall = call ?: coreContext.core.currentCall ?: coreContext.core.calls[0]
for (audioDevice in coreContext.core.audioDevices) {
if (audioDevice.type == AudioDevice.Type.Bluetooth && audioDevice.hasCapability(
AudioDevice.Capabilities.CapabilityPlay
)
) {
Log.i("[Audio Route Helper] Found bluetooth audio device [${audioDevice.deviceName}], routing audio to it")
currentCall.outputAudioDevice = audioDevice
return
if (audioDevice.type == AudioDevice.Type.Bluetooth) {
if (audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
Log.i("[Audio Route Helper] Found bluetooth audio device [${audioDevice.deviceName}], routing audio to it")
currentCall.outputAudioDevice = audioDevice
return
}
}
}
Log.e("[Audio Route Helper] Couldn't find bluetooth audio device")
}
fun routeAudioToHeadset(call: Call? = null) {
if (coreContext.core.callsNb == 0) {
Log.e("[Audio Route Helper] No call found, aborting headset audio route change")
return
}
val currentCall = call ?: coreContext.core.currentCall ?: coreContext.core.calls[0]
for (audioDevice in coreContext.core.audioDevices) {
if (audioDevice.type == AudioDevice.Type.Headphones || audioDevice.type == AudioDevice.Type.Headset) {
if (audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
Log.i("[Audio Route Helper] Found headset audio device [${audioDevice.deviceName}], routing audio to it")
currentCall.outputAudioDevice = audioDevice
return
}
}
}
Log.e("[Audio Route Helper] Couldn't find headset audio device")
}
fun isBluetoothAudioRouteCurrentlyUsed(call: Call? = null): Boolean {
if (coreContext.core.callsNb == 0) {
Log.w("[Audio Route Helper] No call found, so bluetooth audio route isn't used")
@ -94,10 +112,8 @@ class AudioRouteUtils {
fun isBluetoothAudioRouteAvailable(): Boolean {
for (audioDevice in coreContext.core.audioDevices) {
if (audioDevice.type == AudioDevice.Type.Bluetooth && audioDevice.hasCapability(
AudioDevice.Capabilities.CapabilityPlay
)
) {
if (audioDevice.type == AudioDevice.Type.Bluetooth &&
audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
Log.i("[Audio Route Helper] Found bluetooth audio device [${audioDevice.deviceName}]")
return true
}
@ -107,7 +123,8 @@ class AudioRouteUtils {
fun isHeadsetAudioRouteAvailable(): Boolean {
for (audioDevice in coreContext.core.audioDevices) {
if (audioDevice.type == AudioDevice.Type.Headset || audioDevice.type == AudioDevice.Type.Headphones) {
if ((audioDevice.type == AudioDevice.Type.Headset || audioDevice.type == AudioDevice.Type.Headphones) &&
audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
Log.i("[Audio Route Helper] Found headset/headphones audio device [${audioDevice.deviceName}]")
return true
}