audiopolicy: Wrong device selection for music during concurrency.
Music playback is switching from proxy device to speaker when more than
one touch tone/notification streams are started after music and one of
the low latency streams is stopped.
Consider low latency streams playing on speaker and music playing
on WiFi display (proxy device).
When the first low latency output is stopped, getNewOutputDevices checks
for a product strategy from the list. STRATEGY_SONIFICATION comes prior to
STRATEGY_MEDIA in the list of product strategies. If an ALARM or
ENFORCED_AUDIBLE stream is supported by the product strategy, devices are
returned for STRATEGY_SONIFICATION without checking whether the stream is
associated to the output descriptor for which we are querying devices.
As a solution, we check if ALARM or ENFORCED_AUDIBLE streams are active
on the queried output descriptor and return devices accordingly.
Bug: 137907302
Test: manual audio smoke tests.
authored-by: Manisha Agarwal <maniagar@codeaurora.org>
Change-Id: I49ea4d01290b4a611df281681c0db9fe3f7957fc
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8d11c16..e82691f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5721,13 +5721,27 @@
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
StreamTypeVector streams = mEngine->getStreamTypesForProductStrategy(productStrategy);
auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front();
+ auto hasStreamActive = [&](auto stream) {
+ return hasStream(streams, stream) && isStreamActive(stream, 0);
+ };
- if ((hasVoiceStream(streams) &&
- (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) &&
- !isStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE, 0)) ||
- ((hasStream(streams, AUDIO_STREAM_ALARM) || hasStream(streams, AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
- mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) ||
- outputDesc->isStrategyActive(productStrategy)) {
+ auto doGetOutputDevicesForVoice = [&]() {
+ return hasVoiceStream(streams) && (outputDesc == mPrimaryOutput ||
+ outputDesc->isActive(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) &&
+ (isInCall() ||
+ mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc));
+ };
+
+ // With low-latency playing on speaker, music on WFD, when the first low-latency
+ // output is stopped, getNewOutputDevices checks for a product strategy
+ // from the list, as STRATEGY_SONIFICATION comes prior to STRATEGY_MEDIA.
+ // If an ALARM or ENFORCED_AUDIBLE stream is supported by the product strategy,
+ // devices are returned for STRATEGY_SONIFICATION without checking whether the
+ // stream is associated to the output descriptor.
+ if (doGetOutputDevicesForVoice() || outputDesc->isStrategyActive(productStrategy) ||
+ ((hasStreamActive(AUDIO_STREAM_ALARM) ||
+ hasStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
+ mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) {
// Retrieval of devices for voice DL is done on primary output profile, cannot
// check the route (would force modifying configuration file for this profile)
devices = mEngine->getOutputDevicesForAttributes(attr, nullptr, fromCache);