audio policy: exclude A2DP and LE Audio whenever SCO is active
Add exclusion of A2DP and LE Audio devices from available output devices
in Engine::filterOutputDevicesForStrategy() when SCO audio is potentially
in use:
1) a call is active and SCO is the preferred device for the PHONE strategy
2) a given strategy is active and SCO is the preferred device for this
strategy
3) a ringtone is active and we must ring over SCO.
4) a capture is active from BT SCO
Bug: 292037886
Test: make
Flag: EXEMPT bug fix.
Change-Id: Ic12090033dfa8f80f29b571778b4e88eb42c347e
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 799b8d9..aec8c16 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -30,6 +30,7 @@
"libaudiopolicyengine_config",
],
shared_libs: [
+ "com.android.media.audioserver-aconfig-cc",
"libaudio_aidl_conversion_common_cpp",
"libaudiofoundation",
"libaudiopolicy",
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 13cc165..406bc4f 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -30,6 +30,7 @@
#include <PolicyAudioPort.h>
#include <IOProfile.h>
#include <AudioIODescriptorInterface.h>
+#include <com_android_media_audioserver.h>
#include <policy.h>
#include <media/AudioContainers.h>
#include <utils/String8.h>
@@ -154,12 +155,58 @@
return EngineBase::setForceUse(usage, config);
}
+bool Engine::isBtScoActive(DeviceVector& availableOutputDevices,
+ const SwAudioOutputCollection &outputs) const {
+ if (availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+ return false;
+ }
+ // SCO is active if:
+ // 1) we are in a call and SCO is the preferred device for PHONE strategy
+ if (isInCall() && audio_is_bluetooth_out_sco_device(
+ getPreferredDeviceTypeForLegacyStrategy(availableOutputDevices, STRATEGY_PHONE))) {
+ return true;
+ }
+
+ // 2) A strategy for which the preferred device is SCO is active
+ for (const auto &ps : getOrderedProductStrategies()) {
+ if (outputs.isStrategyActive(ps) &&
+ !getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps)
+ .getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+ return true;
+ }
+ }
+ // 3) a ringtone is active and SCO is used for ringing
+ if (outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_RING))
+ && (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
+ == AUDIO_POLICY_FORCE_BT_SCO)) {
+ return true;
+ }
+ // 4) an active input is routed from SCO
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ const auto &inputs = getApmObserver()->getInputs();
+ if (inputs.activeInputsCountOnDevices(availableInputDevices.getDevicesFromType(
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) > 0) {
+ return true;
+ }
+ return false;
+}
+
void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
DeviceVector& availableOutputDevices,
const SwAudioOutputCollection &outputs) const
{
DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ if (com::android::media::audioserver::use_bt_sco_for_media()) {
+ // remove A2DP and LE Audio devices whenever BT SCO is in use
+ if (isBtScoActive(availableOutputDevices, outputs)) {
+ availableOutputDevices.remove(
+ availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllA2dpSet()));
+ availableOutputDevices.remove(
+ availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllBleSet()));
+ }
+ }
+
switch (strategy) {
case STRATEGY_SONIFICATION_RESPECTFUL: {
if (!(isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
@@ -418,15 +465,27 @@
getLastRemovableMediaDevices(GROUP_WIRED, excludedDevices));
}
}
+
+ if (com::android::media::audioserver::use_bt_sco_for_media()) {
+ if (devices2.isEmpty() && isBtScoActive(availableOutputDevices, outputs)) {
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+ { AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+ }
+ }
+
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
devices2 = availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
+
if (devices2.isEmpty()) {
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
}
+
DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
// ARC, SPDIF and AUX_LINE can co-exist with others.
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 878bca9..a6090cf 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -109,6 +109,9 @@
DeviceVector getDisabledDevicesForInputSource(
const DeviceVector& availableInputDevices, audio_source_t inputSource) const;
+ bool isBtScoActive(DeviceVector& availableOutputDevices,
+ const SwAudioOutputCollection &outputs) const;
+
std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap;
};
} // namespace audio_policy