Preference multichannel pcm direct output over stereo mixer
If a direct output is available for a multichannel output request,
and the mixer outputs a channel count lower than the track, try the
direct output first, and fall-back to the non-direct output if
not successful.
Bug: 238286324
Test: atest audiopolicy_tests:AudioPolicyManagerCarTest#GetOutputForAttrAtmosOutputAfterRegisteringPolicyMix
Change-Id: Ic7265bd09556ab7dd0660df5b307d151abace503
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 6536e90..912d53a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1186,19 +1186,27 @@
primaryMix->mDeviceAddress,
AUDIO_FORMAT_DEFAULT);
sp<SwAudioOutputDescriptor> policyDesc = primaryMix->getOutput();
- if (deviceDesc != nullptr
- && (policyDesc == nullptr || (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT))) {
+ bool tryDirectForFlags = policyDesc == nullptr ||
+ (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT);
+ // if a direct output can be opened to deliver the track's multi-channel content to the
+ // output rather than being downmixed by the primary output, then use this direct
+ // output by by-passing the primary mix if possible, otherwise fall-through to primary
+ // mix.
+ bool tryDirectForChannelMask = policyDesc != nullptr
+ && (audio_channel_count_from_out_mask(policyDesc->getConfig().channel_mask) <
+ audio_channel_count_from_out_mask(config->channel_mask));
+ if (deviceDesc != nullptr && (tryDirectForFlags || tryDirectForChannelMask)) {
audio_io_handle_t newOutput;
status = openDirectOutput(
*stream, session, config,
(audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT),
DeviceVector(deviceDesc), &newOutput);
- if (status != NO_ERROR) {
- policyDesc = nullptr;
- } else {
+ if (status == NO_ERROR) {
policyDesc = mOutputs.valueFor(newOutput);
primaryMix->setOutput(policyDesc);
- }
+ } else if (tryDirectForFlags) {
+ policyDesc = nullptr;
+ } // otherwise use primary if available.
}
if (policyDesc != nullptr) {
policyDesc->mPolicyMix = primaryMix;
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 4fd750a..43b1a2a 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -1733,7 +1733,7 @@
dumpToLog();
}
-TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrEncodedOutputAfterRegisteringPolicyMix) {
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrAtmosOutputAfterRegisteringPolicyMix) {
status_t ret;
audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
const std::string kTestBusMediaOutput = "bus0_media_out";
@@ -1752,6 +1752,18 @@
ASSERT_EQ(AUDIO_FORMAT_E_AC3_JOC, outDesc->getFormat());
ASSERT_EQ(AUDIO_CHANNEL_OUT_5POINT1, outDesc->getChannelMask());
ASSERT_EQ(k48000SamplingRate, outDesc->getSamplingRate());
+
+ selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ output = AUDIO_IO_HANDLE_NONE;
+ portId = AUDIO_PORT_HANDLE_NONE;
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_7POINT1POINT4,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId);
+ ASSERT_NE(AUDIO_PORT_HANDLE_NONE, selectedDeviceId);
+ outDesc = mManager->getOutputs().valueFor(output);
+ ASSERT_NE(nullptr, outDesc.get());
+ ASSERT_EQ(AUDIO_FORMAT_PCM_16_BIT, outDesc->getFormat());
+ ASSERT_EQ(AUDIO_CHANNEL_OUT_7POINT1POINT4, outDesc->getChannelMask());
+ ASSERT_EQ(k48000SamplingRate, outDesc->getSamplingRate());
}
class AudioPolicyManagerTVTest : public AudioPolicyManagerTestWithConfigurationFile {
diff --git a/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml b/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
index e3b2838..d131ed8 100644
--- a/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
@@ -55,6 +55,12 @@
samplingRates="48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1"/>
</mixPort>
+ <mixPort name="mixport_bus0_media_out_atmos_pcm" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+ </mixPort>
<mixPort name="mixport_bus1_navigation_out" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000"
@@ -129,6 +135,8 @@
<profile name="" format="AUDIO_FORMAT_E_AC3_JOC"
samplingRates="48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1"/>
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
<gains>
<gain name="" mode="AUDIO_GAIN_MODE_JOINT"
minValueMB="-3200" maxValueMB="600" defaultValueMB="0"
@@ -276,7 +284,7 @@
<!-- route declaration, i.e. list all available sources for a given sink -->
<routes>
<route type="mix" sink="bus0_media_out"
- sources="mixport_bus0_media_out,mixport_bus0_media_out_atmos"/>
+ sources="mixport_bus0_media_out,mixport_bus0_media_out_atmos,mixport_bus0_media_out_atmos_pcm"/>
<route type="mix" sink="bus1_navigation_out" sources="mixport_bus1_navigation_out"/>
<route type="mix" sink="bus2_voice_command_out"
sources="mixport_bus2_voice_command_out"/>