Add MSD support in getDirectProfilesForAttributes
Enabled an AudioProfile equality comparison that
can ignore the dynamic flags.
Add unit tests for the MSD cases.
Bug: 214971780
Test: atest audiopolicy_tests
Test: atest android.media.audio.cts.DirectAudioProfilesForAttributesTest
Change-Id: Ic72048c9d134c02a79678b8b41f1fb1201ae7086
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 734fa9c..2170cd8 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -127,16 +127,17 @@
"%*s%s\n", spaces, "", audio_encapsulation_type_to_string(mEncapsulationType)));
}
-bool AudioProfile::equals(const sp<AudioProfile>& other) const
+bool AudioProfile::equals(const sp<AudioProfile>& other, bool ignoreDynamicFlags) const
{
return other != nullptr &&
mName.compare(other->mName) == 0 &&
mFormat == other->getFormat() &&
mChannelMasks == other->getChannels() &&
mSamplingRates == other->getSampleRates() &&
- mIsDynamicFormat == other->isDynamicFormat() &&
- mIsDynamicChannels == other->isDynamicChannels() &&
- mIsDynamicRate == other->isDynamicRate() &&
+ (ignoreDynamicFlags ||
+ (mIsDynamicFormat == other->isDynamicFormat() &&
+ mIsDynamicChannels == other->isDynamicChannels() &&
+ mIsDynamicRate == other->isDynamicRate())) &&
mEncapsulationType == other->getEncapsulationType();
}
@@ -326,10 +327,10 @@
return false;
}
-bool AudioProfileVector::contains(const sp<AudioProfile>& profile) const
+bool AudioProfileVector::contains(const sp<AudioProfile>& profile, bool ignoreDynamicFlags) const
{
for (const auto& audioProfile : *this) {
- if (audioProfile->equals(profile)) {
+ if (audioProfile->equals(profile, ignoreDynamicFlags)) {
return true;
}
}
@@ -356,6 +357,14 @@
});
}
+void AudioProfileVector::addAllValidProfiles(const AudioProfileVector& audioProfiles) {
+ for (const auto& audioProfile : audioProfiles) {
+ if (audioProfile->isValid() && !contains(audioProfile, true /*ignoreDynamicFlags*/)) {
+ add(audioProfile);
+ }
+ }
+}
+
ConversionResult<AudioProfileVector>
aidl2legacy_AudioProfileVector(const AudioProfileVector::Aidl& aidl, bool isInput) {
return convertContainers<AudioProfileVector>(aidl.first, aidl.second,
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index c3a0fb2..79dfd12 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -78,7 +78,7 @@
void dump(std::string *dst, int spaces) const;
- bool equals(const sp<AudioProfile>& other) const;
+ bool equals(const sp<AudioProfile>& other, bool ignoreDynamicFlags = false) const;
using Aidl = std::pair<media::audio::common::AudioProfile, media::AudioProfileSys>;
ConversionResult<Aidl> toParcelable(bool isInput) const;
@@ -139,11 +139,12 @@
bool hasDynamicProfile() const;
bool hasDynamicRateFor(audio_format_t format) const;
- bool contains(const sp<AudioProfile>& profile) const;
+ bool contains(const sp<AudioProfile>& profile, bool ignoreDynamicFlags = false) const;
virtual void dump(std::string *dst, int spaces) const;
bool equals(const AudioProfileVector& other) const;
+ void addAllValidProfiles(const AudioProfileVector& audioProfiles);
using Aidl = std::pair<
std::vector<media::audio::common::AudioProfile>,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cc36c08..4bade63 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1709,6 +1709,28 @@
}
}
+bool AudioPolicyManager::msdHasPatchesToAllDevices(const AudioDeviceTypeAddrVector& devices) {
+ DeviceVector devicesToCheck = mOutputDevicesAll.getDevicesFromDeviceTypeAddrVec(devices);
+ AudioPatchCollection msdPatches = getMsdOutputPatches();
+ for (size_t i = 0; i < msdPatches.size(); i++) {
+ const auto& patch = msdPatches[i];
+ for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
+ const struct audio_port_config *sink = &patch->mPatch.sinks[j];
+ if (sink->type == AUDIO_PORT_TYPE_DEVICE) {
+ const auto& foundDevice = devicesToCheck.getDevice(
+ sink->ext.device.type, String8(sink->ext.device.address), AUDIO_FORMAT_DEFAULT);
+ if (foundDevice != nullptr) {
+ devicesToCheck.remove(foundDevice);
+ if (devicesToCheck.isEmpty()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags,
audio_format_t format,
@@ -3895,31 +3917,41 @@
}
for (const auto& hwModule : mHwModules) {
- for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (!curProfile->asAudioPort()->isDirectOutput()) {
+ // the MSD module checks for different conditions
+ if (strcmp(hwModule->getName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0) {
+ continue;
+ }
+ for (const auto& outputProfile : hwModule->getOutputProfiles()) {
+ if (!outputProfile->asAudioPort()->isDirectOutput()) {
continue;
}
- // Allow only profiles that support all the available and routed devices
- DeviceVector supportedDevices = curProfile->getSupportedDevices();
- if (supportedDevices.getDevicesFromDeviceTypeAddrVec(devices).size()
+ // allow only profiles that support all the available and routed devices
+ if (outputProfile->getSupportedDevices().getDevicesFromDeviceTypeAddrVec(devices).size()
!= devices.size()) {
continue;
}
-
- const auto audioProfiles = curProfile->asAudioPort()->getAudioProfiles();
- ALOGV("%s: found direct profile (%s) with %zu audio profiles.",
- __func__, curProfile->getTagName().c_str(), audioProfiles.size());
- for (const auto& audioProfile : audioProfiles) {
- if (audioProfile->isValid() && !audioProfilesVector.contains(audioProfile)
- // TODO - why do we have same PCM format with both dynamic and non dynamic format
- && audioProfile->isDynamicFormat()) {
- ALOGV("%s: adding audio profile with encoding (%d).",
- __func__, audioProfile->getFormat());
- audioProfilesVector.add(audioProfile);
- }
- }
+ audioProfilesVector.addAllValidProfiles(
+ outputProfile->asAudioPort()->getAudioProfiles());
}
}
+
+ // add the direct profiles from MSD if present and has audio patches to all the output(s)
+ const auto& msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != nullptr) {
+ if (msdHasPatchesToAllDevices(devices)) {
+ ALOGV("%s: MSD audio patches set to all output devices.", __func__);
+ for (const auto& outputProfile : msdModule->getOutputProfiles()) {
+ if (!outputProfile->asAudioPort()->isDirectOutput()) {
+ continue;
+ }
+ audioProfilesVector.addAllValidProfiles(
+ outputProfile->asAudioPort()->getAudioProfiles());
+ }
+ } else {
+ ALOGV("%s: MSD audio patches NOT set to all output devices.", __func__);
+ }
+ }
+
return NO_ERROR;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a145c70..587dd60 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -909,6 +909,7 @@
PatchBuilder buildMsdPatch(bool msdIsSource, const sp<DeviceDescriptor> &device) const;
status_t setMsdOutputPatches(const DeviceVector *outputDevices = nullptr);
void releaseMsdOutputPatches(const DeviceVector& devices);
+ bool msdHasPatchesToAllDevices(const AudioDeviceTypeAddrVector& devices);
// Overload of setDeviceConnectionState()
status_t setDeviceConnectionState(audio_devices_t deviceType,
@@ -1120,6 +1121,10 @@
bool isOffloadPossible(const audio_offload_info_t& offloadInfo,
bool durationIgnored = false);
+ // adds the profiles from the outputProfile to the passed audioProfilesVector
+ // without duplicating them if already present
+ void addPortProfilesToVector(sp<IOProfile> outputProfile,
+ AudioProfileVector& audioProfilesVector);
};
};
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 9c1adc6..693f973 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -373,6 +373,7 @@
protected:
void SetUpManagerConfig() override;
void TearDown() override;
+ AudioProfileVector getDirectProfilesForAttributes(const audio_attributes_t& attr);
sp<DeviceDescriptor> mMsdOutputDevice;
sp<DeviceDescriptor> mMsdInputDevice;
@@ -502,6 +503,13 @@
AudioPolicyManagerTest::TearDown();
}
+AudioProfileVector AudioPolicyManagerTestMsd::getDirectProfilesForAttributes(
+ const audio_attributes_t& attr) {
+ AudioProfileVector audioProfilesVector;
+ mManager->getDirectProfilesForAttributes(&attr, audioProfilesVector);
+ return audioProfilesVector;
+}
+
TEST_P(AudioPolicyManagerTestMsd, InitSuccess) {
ASSERT_TRUE(mMsdOutputDevice);
ASSERT_TRUE(mMsdInputDevice);
@@ -642,6 +650,48 @@
ASSERT_EQ(1, patchCount.deltaFromSnapshot());
}
+TEST_P(AudioPolicyManagerTestMsd, GetDirectProfilesForAttributesWithMsd) {
+ const audio_attributes_t attr = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ // count expected direct profiles for the default device
+ int countDirectProfilesPrimary = 0;
+ const auto& primary = mManager->getConfig().getHwModules()
+ .getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
+ for (const auto outputProfile : primary->getOutputProfiles()) {
+ if (outputProfile->asAudioPort()->isDirectOutput()) {
+ countDirectProfilesPrimary += outputProfile->asAudioPort()->getAudioProfiles().size();
+ }
+ }
+
+ // count expected direct profiles for the msd device
+ int countDirectProfilesMsd = 0;
+ const auto& msd = mManager->getConfig().getHwModules()
+ .getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ for (const auto outputProfile : msd->getOutputProfiles()) {
+ if (outputProfile->asAudioPort()->isDirectOutput()) {
+ countDirectProfilesMsd += outputProfile->asAudioPort()->getAudioProfiles().size();
+ }
+ }
+
+ // before setting up MSD audio patches we only have the primary hal direct profiles
+ ASSERT_EQ(countDirectProfilesPrimary, getDirectProfilesForAttributes(attr).size());
+
+ DeviceVector outputDevices = mManager->getAvailableOutputDevices();
+ // Remove MSD output device to avoid patching to itself
+ outputDevices.remove(mMsdOutputDevice);
+ mManager->setMsdOutputPatches(&outputDevices);
+
+ // after setting up MSD audio patches the MSD direct profiles are added
+ ASSERT_EQ(countDirectProfilesPrimary + countDirectProfilesMsd,
+ getDirectProfilesForAttributes(attr).size());
+
+ mManager->releaseMsdOutputPatches(outputDevices);
+ // releasing the MSD audio patches gets us back to the primary hal direct profiles only
+ ASSERT_EQ(countDirectProfilesPrimary, getDirectProfilesForAttributes(attr).size());
+}
+
class AudioPolicyManagerTestWithConfigurationFile : public AudioPolicyManagerTest {
protected:
void SetUpManagerConfig() override;