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/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;
 }