audio policy: refine strategy invalidation logic take two
This reverts commit ea04dff4 and adds a proper fix
for b/140545518 to commit 8bbd0e14.
Direct outputs should follow a different logic for client invalidation
than mixer outputs.
Bug: 140545518
Test: audio smoke tests while verifying no audioserver crash.
Change-Id: Ia59803f10a7eeb2f02803b9a07630c744a37bf02
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0f52397..1f8ceec 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5064,10 +5064,12 @@
// also take into account external policy-related changes: add all outputs which are
// associated with policies in the "before" and "after" output vectors
ALOGVV("%s(): policy related outputs", __func__);
+ bool hasDynamicPolicy = false;
for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) {
const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i);
if (desc != 0 && desc->mPolicyMix != NULL) {
srcOutputs.add(desc->mIoHandle);
+ hasDynamicPolicy = true;
ALOGVV(" previous outputs: adding %d", desc->mIoHandle);
}
}
@@ -5075,6 +5077,7 @@
const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != 0 && desc->mPolicyMix != NULL) {
dstOutputs.add(desc->mIoHandle);
+ hasDynamicPolicy = true;
ALOGVV(" new outputs: adding %d", desc->mIoHandle);
}
}
@@ -5083,12 +5086,45 @@
// get maximum latency of all source outputs to determine the minimum mute time guaranteeing
// audio from invalidated tracks will be rendered when unmuting
uint32_t maxLatency = 0;
+ bool invalidate = hasDynamicPolicy;
for (audio_io_handle_t srcOut : srcOutputs) {
sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
- if (desc != 0 && maxLatency < desc->latency()) {
+ if (desc == nullptr) continue;
+
+ if (desc->isStrategyActive(psId) && maxLatency < desc->latency()) {
maxLatency = desc->latency();
}
+
+ if (invalidate) continue;
+
+ for (auto client : desc->clientsList(false /*activeOnly*/)) {
+ if (!desc->mProfile->isDirectOutput()) {
+ // a client on a non direct outputs has necessarily a linear PCM format
+ // so we can call selectOutput() safely
+ const audio_io_handle_t newOutput = selectOutput(dstOutputs,
+ client->flags(),
+ client->config().format,
+ client->config().channel_mask,
+ client->config().sample_rate);
+ if (newOutput != srcOut) {
+ invalidate = true;
+ break;
+ }
+ } else {
+ sp<IOProfile> profile = getProfileForOutput(newDevices,
+ client->config().sample_rate,
+ client->config().format,
+ client->config().channel_mask,
+ client->flags(),
+ true /* directOnly */);
+ if (profile != desc->mProfile) {
+ invalidate = true;
+ break;
+ }
+ }
+ }
}
+
ALOGV_IF(!(srcOutputs.isEmpty() || dstOutputs.isEmpty()),
"%s: strategy %d, moving from output %s to output %s", __func__, psId,
std::to_string(srcOutputs[0]).c_str(),
@@ -5096,7 +5132,9 @@
// mute strategy while moving tracks from one output to another
for (audio_io_handle_t srcOut : srcOutputs) {
sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
- if (desc != 0 && desc->isStrategyActive(psId)) {
+ if (desc == nullptr) continue;
+
+ if (desc->isStrategyActive(psId)) {
setStrategyMute(psId, true, desc);
setStrategyMute(psId, false, desc, maxLatency * LATENCY_MUTE_FACTOR,
newDevices.types());
@@ -5112,8 +5150,10 @@
selectOutputForMusicEffects();
}
// Move tracks associated to this stream (and linked) from previous output to new output
- for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) {
- mpClientInterface->invalidateStream(stream);
+ if (invalidate) {
+ for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) {
+ mpClientInterface->invalidateStream(stream);
+ }
}
}
}