From 2a836c02ef6b2371b487a78cd609c30d92410b10 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Wed, 15 Feb 2023 21:10:23 +0200 Subject: [PATCH] Embedded audio mode change to audio focus request --- .../com/tutpro/baresip/BaresipService.kt | 117 +++++++++--------- .../kotlin/com/tutpro/baresip/MainActivity.kt | 33 +++-- .../main/kotlin/com/tutpro/baresip/Utils.kt | 1 + 3 files changed, 82 insertions(+), 69 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt index 5d67ce60..6a11b7a0 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt @@ -65,9 +65,7 @@ class BaresipService: Service() { private var rt: Ringtone? = null private var rtTimer: Timer? = null - private var audioFocusRequest: AudioFocusRequestCompat? = null private var origVolume = mutableMapOf() - private var btAdapter: BluetoothAdapter? = null private var linkAddresses = mutableMapOf() private var activeNetwork: Network? = null private var allNetworks = mutableSetOf() @@ -457,9 +455,7 @@ class BaresipService: Service() { val vidMode = intent.getIntExtra("video", Api.VIDMODE_OFF) stopRinging() stopMediaPlayer() - if (am.mode != AudioManager.MODE_IN_COMMUNICATION) - am.mode = AudioManager.MODE_IN_COMMUNICATION - requestAudioFocus(AudioAttributes.CONTENT_TYPE_SPEECH) + requestAudioFocus(am, AudioAttributes.CONTENT_TYPE_SPEECH) setCallVolume() proximitySensing(true) Api.ua_answer(uap, callp, vidMode) @@ -637,7 +633,6 @@ class BaresipService: Service() { if (call!!.status == "transferring") break stopMediaPlayer() - requestAudioFocus(AudioAttributes.CONTENT_TYPE_SPEECH) setCallVolume() proximitySensing(true) return @@ -879,7 +874,7 @@ class BaresipService: Service() { resetCallVolume() am.mode = AudioManager.MODE_NORMAL am.stopBluetoothSco() - abandonAudioFocus() + abandonAudioFocus(am) proximitySensing(false) } val missed = call.startTime == null && call.dir == "in" && !call.rejected @@ -1173,57 +1168,8 @@ class BaresipService: Service() { return spannable } - - @SuppressLint("MissingPermission") - private fun isBluetoothHeadsetConnected(): Boolean { - return if (VERSION.SDK_INT < 31) - btAdapter != null && btAdapter!!.isEnabled && - btAdapter!!.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothAdapter.STATE_CONNECTED - else - // getProfileConnectionState requires asking fot BLUETOOTH_CONNECT permission - true - } - - private fun requestAudioFocus(type: Int) { - if (audioFocusRequest != null) { - if (audioFocusRequest!!.audioAttributesCompat.contentType == type) - return - else - abandonAudioFocus() - } - val attributes = AudioAttributesCompat.Builder() - .setUsage(AudioAttributesCompat.USAGE_VOICE_COMMUNICATION) - .setContentType(type) - .build() - audioFocusRequest = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN_TRANSIENT) - .setAudioAttributes(attributes) - .setOnAudioFocusChangeListener { } - .build() - if (AudioManagerCompat.requestAudioFocus(am, audioFocusRequest!!) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { - Log.d(TAG, "Audio focus granted") - isAudioFocused = true - if (isBluetoothHeadsetConnected() && !am.isBluetoothScoOn) { - Log.d(TAG, "Starting Bluetooth SCO") - am.startBluetoothSco() - } - } else { - Log.d(TAG, "Audio focus denied") - audioFocusRequest = null - isAudioFocused = false - } - } - - private fun abandonAudioFocus() { - if (audioFocusRequest != null) { - AudioManagerCompat.abandonAudioFocusRequest(am, audioFocusRequest!!) - audioFocusRequest = null - isAudioFocused = false - Log.d(TAG, "Audio focus abandoned") - } - } - private fun startRinging() { - requestAudioFocus(AudioAttributes.CONTENT_TYPE_MUSIC) + requestAudioFocus(am, AudioAttributes.CONTENT_TYPE_MUSIC) am.mode = AudioManager.MODE_RINGTONE if (rt == null) { val rtUri = RingtoneManager.getActualDefaultRingtoneUri(applicationContext, @@ -1248,7 +1194,7 @@ class BaresipService: Service() { private fun stopRinging() { if (am.mode == AudioManager.MODE_RINGTONE) - abandonAudioFocus() + abandonAudioFocus(am) if (VERSION.SDK_INT < 28 && rtTimer != null) { rtTimer!!.cancel() rtTimer = null @@ -1485,7 +1431,7 @@ class BaresipService: Service() { if (am.isBluetoothScoOn) am.stopBluetoothSco() am.mode = AudioManager.MODE_NORMAL - abandonAudioFocus() + abandonAudioFocus(am) stopRinging() stopMediaPlayer() uas.clear() @@ -1541,6 +1487,59 @@ class BaresipService: Service() { val serviceEvent = MutableLiveData>() val serviceEvents = mutableListOf() + private var audioFocusRequest: AudioFocusRequestCompat? = null + private var btAdapter: BluetoothAdapter? = null + + fun requestAudioFocus(am: AudioManager, type: Int): Boolean { + if (audioFocusRequest != null) { + if (audioFocusRequest!!.audioAttributesCompat.contentType == type) + return true + else + abandonAudioFocus(am) + } + val attributes = AudioAttributesCompat.Builder() + .setUsage(AudioAttributesCompat.USAGE_VOICE_COMMUNICATION) + .setContentType(type) + .build() + audioFocusRequest = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN_TRANSIENT) + .setAudioAttributes(attributes) + .setOnAudioFocusChangeListener { } + .build() + if (AudioManagerCompat.requestAudioFocus(am, audioFocusRequest!!) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + Log.d(TAG, "Audio focus granted") + isAudioFocused = true + if (isBluetoothHeadsetConnected() && !am.isBluetoothScoOn) { + Log.d(TAG, "Starting Bluetooth SCO") + am.startBluetoothSco() + } + if (type == AudioAttributes.CONTENT_TYPE_SPEECH) + am.mode = AudioManager.MODE_IN_COMMUNICATION + } else { + Log.d(TAG, "Audio focus denied") + audioFocusRequest = null + isAudioFocused = false + } + return isAudioFocused + } + + private fun abandonAudioFocus(am: AudioManager) { + if (audioFocusRequest != null) { + AudioManagerCompat.abandonAudioFocusRequest(am, audioFocusRequest!!) + audioFocusRequest = null + isAudioFocused = false + Log.d(TAG, "Audio focus abandoned") + } + } + + @SuppressLint("MissingPermission") + private fun isBluetoothHeadsetConnected(): Boolean { + return if (VERSION.SDK_INT < 31) + btAdapter != null && btAdapter!!.isEnabled && + btAdapter!!.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothAdapter.STATE_CONNECTED + else + // getProfileConnectionState requires asking for BLUETOOTH_CONNECT permission + true + } } diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index ec7f895f..537dacf5 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -10,6 +10,7 @@ import android.content.* import android.content.Intent.ACTION_CALL import android.content.pm.PackageManager import android.content.res.Configuration.ORIENTATION_PORTRAIT +import android.media.AudioAttributes import android.media.AudioDeviceInfo import android.media.AudioManager import android.net.Uri @@ -1816,17 +1817,24 @@ class MainActivity : AppCompatActivity() { hangupButton.visibility = View.VISIBLE hangupButton.isEnabled = true if (Build.VERSION.SDK_INT < 31) { - am.mode = AudioManager.MODE_IN_COMMUNICATION - callRunnable = Runnable { - callRunnable = null - if (!call(ua, uri)) { - callButton.visibility = View.VISIBLE - callButton.isEnabled = true - hangupButton.visibility = View.INVISIBLE - hangupButton.isEnabled = false + if (!BaresipService.requestAudioFocus(am, AudioAttributes.CONTENT_TYPE_SPEECH)) { + Toast.makeText( + applicationContext, + "Audio focus denied", + Toast.LENGTH_SHORT + ).show() + } else { + callRunnable = Runnable { + callRunnable = null + if (!call(ua, uri)) { + callButton.visibility = View.VISIBLE + callButton.isEnabled = true + hangupButton.visibility = View.INVISIBLE + hangupButton.isEnabled = false + } } + callHandler.postDelayed(callRunnable!!, 1000) } - callHandler.postDelayed(callRunnable!!, 1000) } else { audioModeChangedListener = AudioManager.OnModeChangedListener { mode -> if (mode == AudioManager.MODE_IN_COMMUNICATION) { @@ -1849,7 +1857,12 @@ class MainActivity : AppCompatActivity() { } am.addOnModeChangedListener(mainExecutor, audioModeChangedListener!!) Log.d(TAG, "Setting audio mode to MODE_IN_COMMUNICATION") - am.mode = AudioManager.MODE_IN_COMMUNICATION + if (!BaresipService.requestAudioFocus(am, AudioAttributes.CONTENT_TYPE_SPEECH)) + Toast.makeText( + applicationContext, + "Audio focus denied", + Toast.LENGTH_SHORT + ).show() } } } else { diff --git a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt index b355e7f5..1cbb8ec4 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt @@ -969,4 +969,5 @@ object Utils { else setSpeakerPhone(executor, am, !am.isSpeakerphoneOn) } + }