Add MSD support for isDirectPlaybackSupported
isDirectOutputSupported will now also look into an MSD module if it
exists and check that audio patches are active to all desired output
devices.
Unit tests are included.
Bug: 196047314
Test: atest audiopolicy_tests
Change-Id: Iac23a441dee038b8e70c464d346063ea4162a9d8
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e08ed2a..9bbc1ac 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -935,6 +935,32 @@
ALOGV("setSystemProperty() property %s, value %s", property, value);
}
+// Find an MSD output profile compatible with the parameters passed.
+// When "directOnly" is set, restrict search to profiles for direct outputs.
+sp<IOProfile> AudioPolicyManager::getMsdProfileForOutput(
+ const DeviceVector& devices,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ bool directOnly)
+{
+ flags = getRelevantFlags(flags, directOnly);
+
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != nullptr) {
+ // for the msd module check if there are patches to the output devices
+ if (msdHasPatchesToAllDevices(devices.toTypeAddrVector())) {
+ HwModuleCollection modules;
+ modules.add(msdModule);
+ return searchCompatibleProfileHwModules(
+ modules, getMsdAudioOutDevices(), samplingRate, format, channelMask,
+ flags, directOnly);
+ }
+ }
+ return nullptr;
+}
+
// Find an output profile compatible with the parameters passed. When "directOnly" is set, restrict
// search to profiles for direct outputs.
sp<IOProfile> AudioPolicyManager::getProfileForOutput(
@@ -945,45 +971,65 @@
audio_output_flags_t flags,
bool directOnly)
{
+ flags = getRelevantFlags(flags, directOnly);
+
+ return searchCompatibleProfileHwModules(
+ mHwModules, devices, samplingRate, format, channelMask, flags, directOnly);
+}
+
+audio_output_flags_t AudioPolicyManager::getRelevantFlags (
+ audio_output_flags_t flags, bool directOnly) {
if (directOnly) {
- // only retain flags that will drive the direct output profile selection
- // if explicitly requested
- static const uint32_t kRelevantFlags =
+ // only retain flags that will drive the direct output profile selection
+ // if explicitly requested
+ static const uint32_t kRelevantFlags =
(AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
- AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
- flags =
- (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
+ AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
+ flags = (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
}
+ return flags;
+}
+sp<IOProfile> AudioPolicyManager::searchCompatibleProfileHwModules (
+ const HwModuleCollection& hwModules,
+ const DeviceVector& devices,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ bool directOnly) {
sp<IOProfile> profile;
-
- for (const auto& hwModule : mHwModules) {
+ for (const auto& hwModule : hwModules) {
for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (!curProfile->isCompatibleProfile(devices,
- samplingRate, NULL /*updatedSamplingRate*/,
- format, NULL /*updatedFormat*/,
- channelMask, NULL /*updatedChannelMask*/,
- flags)) {
+ if (!curProfile->isCompatibleProfile(devices,
+ samplingRate, NULL /*updatedSamplingRate*/,
+ format, NULL /*updatedFormat*/,
+ channelMask, NULL /*updatedChannelMask*/,
+ flags)) {
+ continue;
+ }
+ // reject profiles not corresponding to a device currently available
+ if (!mAvailableOutputDevices.containsAtLeastOne(curProfile->getSupportedDevices())) {
+ continue;
+ }
+ // reject profiles if connected device does not support codec
+ if (!curProfile->devicesSupportEncodedFormats(devices.types())) {
+ continue;
+ }
+ if (!directOnly) {
+ return curProfile;
+ }
+
+ // when searching for direct outputs, if several profiles are compatible, give priority
+ // to one with offload capability
+ if (profile != 0 &&
+ ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
continue;
- }
- // reject profiles not corresponding to a device currently available
- if (!mAvailableOutputDevices.containsAtLeastOne(curProfile->getSupportedDevices())) {
- continue;
- }
- // reject profiles if connected device does not support codec
- if (!curProfile->devicesSupportEncodedFormats(devices.types())) {
- continue;
- }
- if (!directOnly) return curProfile;
- // when searching for direct outputs, if several profiles are compatible, give priority
- // to one with offload capability
- if (profile != 0 && ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
- continue;
- }
- profile = curProfile;
- if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
- break;
- }
+ }
+ profile = curProfile;
+ if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ break;
+ }
}
}
return profile;
@@ -3796,7 +3842,22 @@
__FUNCTION__, profile != 0 ? "" : "NOT ",
(profile != 0 ? profile->getTagName().c_str() : "null"),
config.sample_rate, config.format, config.channel_mask, output_flags);
- return (profile != 0);
+
+ // also try the MSD module if compatible profile not found
+ if (profile == nullptr) {
+ profile = getMsdProfileForOutput(outputDevices,
+ config.sample_rate,
+ config.format,
+ config.channel_mask,
+ output_flags,
+ true /* directOnly */);
+ ALOGV("%s() MSD profile %sfound with name: %s, "
+ "sample rate: %u, format: 0x%x, channel_mask: 0x%x, output flags: 0x%x",
+ __FUNCTION__, profile != 0 ? "" : "NOT ",
+ (profile != 0 ? profile->getTagName().c_str() : "null"),
+ config.sample_rate, config.format, config.channel_mask, output_flags);
+ }
+ return (profile != nullptr);
}
bool AudioPolicyManager::isOffloadPossible(const audio_offload_info_t &offloadInfo,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index daa4faf..bc16632 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -737,6 +737,15 @@
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
bool directOnly);
+ /**
+ * Same as getProfileForOutput, but it looks for an MSD profile
+ */
+ sp<IOProfile> getMsdProfileForOutput(const DeviceVector &devices,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ bool directOnly);
audio_io_handle_t selectOutputForMusicEffects();
@@ -1155,6 +1164,21 @@
// without duplicating them if already present
void addPortProfilesToVector(sp<IOProfile> outputProfile,
AudioProfileVector& audioProfilesVector);
+
+ // Searches for a compatible profile with the sample rate, audio format and channel mask
+ // in the list of passed HwModule(s).
+ // returns a compatible profile if found, nullptr otherwise
+ sp<IOProfile> searchCompatibleProfileHwModules (
+ const HwModuleCollection& hwModules,
+ const DeviceVector& devices,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ bool directOnly);
+
+ // Filters only the relevant flags for getProfileForOutput
+ audio_output_flags_t getRelevantFlags (audio_output_flags_t flags, bool directOnly);
};
};
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 551f5e9..d6af886 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -699,6 +699,73 @@
ASSERT_EQ(countDirectProfilesPrimary, getDirectProfilesForAttributes(attr).size());
}
+TEST_P(AudioPolicyManagerTestMsd, IsDirectPlaybackSupportedWithMsd) {
+ const audio_attributes_t attr = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ audio_config_base_t directConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ directConfig.format = AUDIO_FORMAT_DTS;
+ directConfig.sample_rate = 48000;
+ directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+
+ audio_config_base_t nonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ nonDirectConfig.sample_rate = 48000;
+ nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+
+ audio_config_base_t nonExistentConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
+ nonExistentConfig.sample_rate = 48000;
+ nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+
+ audio_config_base_t msdDirectConfig1 = AUDIO_CONFIG_BASE_INITIALIZER;
+ msdDirectConfig1.format = AUDIO_FORMAT_AC3;
+ msdDirectConfig1.sample_rate = 48000;
+ msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+
+ audio_config_base_t msdDirectConfig2 = AUDIO_CONFIG_BASE_INITIALIZER;
+ msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
+ msdDirectConfig2.sample_rate = 48000;
+ msdDirectConfig2.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+
+ audio_config_base_t msdNonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ msdNonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ msdNonDirectConfig.sample_rate = 96000;
+ msdNonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+
+ ASSERT_TRUE(mManager->isDirectOutputSupported(directConfig, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(nonDirectConfig, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(nonExistentConfig, attr));
+ // before setting MSD patches the direct MSD configs return false
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdDirectConfig1, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdDirectConfig2, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdNonDirectConfig, attr));
+
+ DeviceVector outputDevices = mManager->getAvailableOutputDevices();
+ // Remove MSD output device to avoid patching to itself
+ outputDevices.remove(mMsdOutputDevice);
+ mManager->setMsdOutputPatches(&outputDevices);
+
+ ASSERT_TRUE(mManager->isDirectOutputSupported(directConfig, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(nonDirectConfig, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(nonExistentConfig, attr));
+ // after setting MSD patches the direct MSD configs return true
+ ASSERT_TRUE(mManager->isDirectOutputSupported(msdDirectConfig1, attr));
+ ASSERT_TRUE(mManager->isDirectOutputSupported(msdDirectConfig2, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdNonDirectConfig, attr));
+
+ mManager->releaseMsdOutputPatches(outputDevices);
+
+ ASSERT_TRUE(mManager->isDirectOutputSupported(directConfig, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(nonDirectConfig, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(nonExistentConfig, attr));
+ // AFTER releasing MSD patches the direct MSD configs return false
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdDirectConfig1, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdDirectConfig2, attr));
+ ASSERT_FALSE(mManager->isDirectOutputSupported(msdNonDirectConfig, attr));
+}
+
class AudioPolicyManagerTestWithConfigurationFile : public AudioPolicyManagerTest {
protected:
void SetUpManagerConfig() override;