audio policy: LE audio broadcast routing policy
Implement routing policy for LE audio broadcast device.
LE audio broadcast device is only used if:
- No call is active
- Either MEDIA or SONIFICATION_RESPECTFUL is the highest priority active strategy
OR the LE audio unicast device is not active
Bug: 213188698
Test: make
Change-Id: I47eb42066fe41c01867c35b1256241037583420b
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a2ee5f5..a97ca71 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -190,6 +190,9 @@
// save a copy of the opened output descriptors before any output is opened or closed
// by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
mPreviousOutputs = mOutputs;
+
+ bool wasLeUnicastActive = isLeUnicastActive();
+
switch (state)
{
// handle output device connection
@@ -353,6 +356,8 @@
cleanUpForDevice(device);
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, 0);
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
@@ -801,6 +806,7 @@
ALOGV("setPhoneState() state %d", state);
// store previous phone state for management of sonification strategy below
int oldState = mEngine->getPhoneState();
+ bool wasLeUnicastActive = isLeUnicastActive();
if (mEngine->setPhoneState(state) != NO_ERROR) {
ALOGW("setPhoneState() invalid or same state %d", state);
@@ -879,6 +885,8 @@
}
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
+
if (isStateInCall(state)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
// force reevaluating accessibility routing when call starts
@@ -1979,6 +1987,22 @@
return status;
}
+bool AudioPolicyManager::isLeUnicastActive() const {
+ if (isInCall()) {
+ return true;
+ }
+ return isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet());
+}
+
+bool AudioPolicyManager::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+ if (mAvailableOutputDevices.getDevicesFromTypes(deviceTypes).isEmpty()) {
+ return false;
+ }
+ bool active = mOutputs.isAnyDeviceTypeActive(deviceTypes);
+ ALOGV("%s active %d", __func__, active);
+ return active;
+}
+
status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
const sp<TrackClientDescriptor>& client,
uint32_t *delayMs)
@@ -2030,6 +2054,7 @@
// and muting would result in unnecessary delay and dropped audio.
const uint32_t outputLatencyMs = outputDesc->latency();
bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+ bool wasLeUnicastActive = isLeUnicastActive();
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -2153,9 +2178,38 @@
AUDIO_FORMAT_DEFAULT);
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, *delayMs);
+
return NO_ERROR;
}
+void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive,
+ sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs) {
+ bool isUnicastActive = isLeUnicastActive();
+
+ if (wasUnicastActive != isUnicastActive) {
+ //reroute all outputs routed to LE broadcast if LE unicast activy changed on any output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc != ignoredOutput && desc->isActive()
+ && ((isUnicastActive &&
+ !desc->devices().
+ getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST).isEmpty())
+ || (wasUnicastActive &&
+ !desc->devices().getDevicesFromTypes(
+ getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) {
+ DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/);
+ bool force = desc->devices() != newDevices;
+ setOutputDevices(desc, newDevices, force, delayMs);
+ // re-apply device specific volume if not done by setOutputDevice()
+ if (!force) {
+ applyStreamVolumes(desc, newDevices.types(), delayMs);
+ }
+ }
+ }
+ }
+}
+
status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
{
ALOGV("%s portId %d", __FUNCTION__, portId);
@@ -2184,6 +2238,7 @@
// always handle stream stop, check which stream type is stopping
audio_stream_type_t stream = client->stream();
auto clientVolSrc = client->volumeSource();
+ bool wasLeUnicastActive = isLeUnicastActive();
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
@@ -2262,6 +2317,9 @@
if (followsSameRouting(client->attributes(), attributes_initializer(AUDIO_USAGE_MEDIA))) {
selectOutputForMusicEffects();
}
+
+ checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, outputDesc->latency()*2);
+
return NO_ERROR;
} else {
ALOGW("stopOutput() refcount is already 0");
@@ -2337,7 +2395,6 @@
session, flags, toString(*attr).c_str(), *selectedDeviceId);
status_t status = NO_ERROR;
- audio_source_t halInputSource;
audio_attributes_t attributes = *attr;
sp<AudioPolicyMix> policyMix;
sp<DeviceDescriptor> device;
@@ -2408,8 +2465,6 @@
*input = AUDIO_IO_HANDLE_NONE;
*inputType = API_INPUT_INVALID;
- halInputSource = attributes.source;
-
if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
@@ -3570,6 +3625,7 @@
void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
{
uint32_t waitMs = 0;
+ bool wasLeUnicastActive = isLeUnicastActive();
if (updateCallRouting(true /*fromCache*/, delayMs, &waitMs) == NO_ERROR) {
// Only apply special touch sound delay once
delayMs = 0;
@@ -3593,6 +3649,7 @@
applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
}
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
}
void AudioPolicyManager::updateInputRouting() {
@@ -7372,13 +7429,11 @@
return mEngine->getForceUse(usage);
}
-bool AudioPolicyManager::isInCall()
-{
+bool AudioPolicyManager::isInCall() const {
return isStateInCall(mEngine->getPhoneState());
}
-bool AudioPolicyManager::isStateInCall(int state)
-{
+bool AudioPolicyManager::isStateInCall(int state) const {
return is_state_in_call(state);
}