Merge "Pick input profile that partially matches with all flags." into main
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 688772c..c2ee5f6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -73,7 +73,8 @@
     enum CompatibilityScore{
         NO_MATCH = 0,
         PARTIAL_MATCH = 1,
-        EXACT_MATCH = 2
+        PARTIAL_MATCH_WITH_FLAG = 2,
+        EXACT_MATCH = 3
     };
 
     /**
@@ -92,7 +93,6 @@
      * @param channelMask to be checked for compatibility. Must be specified
      * @param updatedChannelMask if non-NULL, it is assigned the actual channel mask
      * @param flags to be checked for compatibility
-     * @param exactMatchRequiredForInputFlags true if exact match is required on flags
      * @return how the IO profile is compatible with the given parameters.
      */
     CompatibilityScore getCompatibilityScore(const DeviceVector &devices,
@@ -103,8 +103,7 @@
                                              audio_channel_mask_t channelMask,
                                              audio_channel_mask_t *updatedChannelMask,
                                              // FIXME parameter type
-                                             uint32_t flags,
-                                             bool exactMatchRequiredForInputFlags = false) const;
+                                             uint32_t flags) const;
 
     /**
      * @brief areAllDevicesSupported: Checks if the given devices are supported by the IO profile.
@@ -119,11 +118,9 @@
      * specified flags.
      *
      * @param flags to be checked for compatibility
-     * @param exactMatchRequiredForInputFlags true if exact match is required on flags
      * @return true if the profile is compatible, false otherwise.
      */
-    bool isCompatibleProfileForFlags(uint32_t flags,
-                                     bool exactMatchRequiredForInputFlags = false) const;
+    bool isCompatibleProfileForFlags(uint32_t flags) const;
 
     void dump(String8 *dst, int spaces) const;
     void log();
@@ -235,6 +232,7 @@
 
 private:
     void refreshMixerBehaviors();
+    CompatibilityScore getFlagsCompatibleScore(uint32_t flags) const;
 
     DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 991b103..bc9eb20 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -42,15 +42,14 @@
         audio_channel_mask_t channelMask,
         audio_channel_mask_t *updatedChannelMask,
         // FIXME type punning here
-        uint32_t flags,
-        bool exactMatchRequiredForInputFlags) const {
+        uint32_t flags) const {
     const bool isPlaybackThread =
             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
     const bool isRecordThread =
             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
     ALOG_ASSERT(isPlaybackThread != isRecordThread);
-    if (!areAllDevicesSupported(devices) ||
-            !isCompatibleProfileForFlags(flags, exactMatchRequiredForInputFlags)) {
+    const auto flagsCompatibleScore = getFlagsCompatibleScore(flags);
+    if (!areAllDevicesSupported(devices) || flagsCompatibleScore == NO_MATCH) {
         return NO_MATCH;
     }
 
@@ -81,7 +80,11 @@
             result = EXACT_MATCH;
         } else if (checkCompatibleAudioProfile(
                 myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) == NO_ERROR) {
-            result = PARTIAL_MATCH;
+            if (flagsCompatibleScore == EXACT_MATCH) {
+                result = PARTIAL_MATCH_WITH_FLAG;
+            } else {
+                result = PARTIAL_MATCH;
+            }
         } else {
             return result;
         }
@@ -118,32 +121,8 @@
     return mSupportedDevices.containsAllDevices(devices);
 }
 
-bool IOProfile::isCompatibleProfileForFlags(uint32_t flags,
-                                            bool exactMatchRequiredForInputFlags) const {
-    const bool isPlaybackThread =
-            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
-    const bool isRecordThread =
-            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
-    ALOG_ASSERT(isPlaybackThread != isRecordThread);
-
-    const uint32_t mustMatchOutputFlags =
-            AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
-    if (isPlaybackThread &&
-        !audio_output_flags_is_subset((audio_output_flags_t)getFlags(),
-                                      (audio_output_flags_t)flags,
-                                      mustMatchOutputFlags)) {
-        return false;
-    }
-    // The only input flag that is allowed to be different is the fast flag.
-    // An existing fast stream is compatible with a normal track request.
-    // An existing normal stream is compatible with a fast track request,
-    // but the fast request will be denied by AudioFlinger and converted to normal track.
-    if (isRecordThread && ((getFlags() ^ flags) &
-            ~(exactMatchRequiredForInputFlags ? AUDIO_INPUT_FLAG_NONE : AUDIO_INPUT_FLAG_FAST))) {
-        return false;
-    }
-
-    return true;
+bool IOProfile::isCompatibleProfileForFlags(uint32_t flags) const {
+    return getFlagsCompatibleScore(flags) != NO_MATCH;
 }
 
 bool IOProfile::containsSingleDeviceSupportingEncodedFormats(
@@ -228,6 +207,39 @@
     }
 }
 
+IOProfile::CompatibilityScore IOProfile::getFlagsCompatibleScore(uint32_t flags) const {
+    const bool isPlaybackThread =
+            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
+    const bool isRecordThread =
+            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
+    ALOG_ASSERT(isPlaybackThread != isRecordThread);
+
+    const uint32_t mustMatchOutputFlags =
+            AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+    if (isPlaybackThread &&
+        !audio_output_flags_is_subset((audio_output_flags_t)getFlags(),
+                                      (audio_output_flags_t)flags,
+                                      mustMatchOutputFlags)) {
+        return NO_MATCH;
+    }
+    // The only input flag that is allowed to be different is the fast flag.
+    // An existing fast stream is compatible with a normal track request.
+    // An existing normal stream is compatible with a fast track request,
+    // but the fast request will be denied by AudioFlinger and converted to normal track.
+    if (isRecordThread) {
+        const auto unmatchedFlag = getFlags() ^ flags;
+        if (unmatchedFlag == AUDIO_INPUT_FLAG_NONE) {
+            return EXACT_MATCH;
+        } else if (unmatchedFlag == AUDIO_INPUT_FLAG_FAST) {
+            return PARTIAL_MATCH;
+        } else {
+            return NO_MATCH;
+        }
+    }
+
+    return EXACT_MATCH;
+}
+
 void IOProfile::dump(String8 *dst, int spaces) const
 {
     String8 extraInfo;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 62cb6c7..0aa3dfc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5025,8 +5025,7 @@
                             nullptr /*updatedFormat*/,
                             mixerAttributes->config.channel_mask,
                             nullptr /*updatedChannelMask*/,
-                            flags,
-                            false /*exactMatchRequiredForInputFlags*/)
+                            flags)
                             != IOProfile::NO_MATCH) {
                 profile = curProfile;
                 break;
@@ -8236,7 +8235,7 @@
     const underlying_input_flag_t oriFlags = flags;
 
     for (;;) {
-        sp<IOProfile> firstInexact = nullptr;
+        sp<IOProfile> inexact = nullptr;
         uint32_t inexactSamplingRate = 0;
         audio_format_t inexactFormat = AUDIO_FORMAT_INVALID;
         audio_channel_mask_t inexactChannelMask = AUDIO_CHANNEL_INVALID;
@@ -8247,7 +8246,7 @@
             for (const auto& profile : hwModule->getInputProfiles()) {
                 // profile->log();
                 //updatedFormat = format;
-                if (profile->getCompatibilityScore(
+                auto compatibleScore = profile->getCompatibilityScore(
                         DeviceVector(device),
                         samplingRate,
                         &updatedSamplingRate,
@@ -8256,27 +8255,16 @@
                         channelMask,
                         &updatedChannelMask,
                         // FIXME ugly cast
-                        (audio_output_flags_t) flags,
-                        true /*exactMatchRequiredForInputFlags*/) == IOProfile::EXACT_MATCH) {
+                        (audio_output_flags_t) flags);
+                if (compatibleScore == IOProfile::EXACT_MATCH) {
                     samplingRate = updatedSamplingRate;
                     format = updatedFormat;
                     channelMask = updatedChannelMask;
                     return profile;
-                }
-                if (firstInexact == nullptr
-                        && profile->getCompatibilityScore(
-                                DeviceVector(device),
-                                samplingRate,
-                                &updatedSamplingRate,
-                                format,
-                                &updatedFormat,
-                                channelMask,
-                                &updatedChannelMask,
-                                // FIXME ugly cast
-                                (audio_output_flags_t) flags,
-                                false /*exactMatchRequiredForInputFlags*/)
-                                != IOProfile::NO_MATCH) {
-                    firstInexact = profile;
+                } else if ((flags != AUDIO_INPUT_FLAG_NONE
+                        && compatibleScore == IOProfile::PARTIAL_MATCH_WITH_FLAG)
+                    || (inexact == nullptr && compatibleScore != IOProfile::NO_MATCH)) {
+                    inexact = profile;
                     inexactSamplingRate = updatedSamplingRate;
                     inexactFormat = updatedFormat;
                     inexactChannelMask = updatedChannelMask;
@@ -8284,11 +8272,11 @@
             }
         }
 
-        if (firstInexact != nullptr) {
+        if (inexact != nullptr) {
             samplingRate = inexactSamplingRate;
             format = inexactFormat;
             channelMask = inexactChannelMask;
-            return firstInexact;
+            return inexact;
         } else if (flags & AUDIO_INPUT_FLAG_RAW) {
             flags = (audio_input_flags_t) (flags & ~AUDIO_INPUT_FLAG_RAW); // retry
         } else if ((flags & mustMatchFlag) == AUDIO_INPUT_FLAG_NONE &&
@@ -9261,8 +9249,7 @@
                                                  : hwModule->getOutputProfiles();
         for (const auto& profile : ioProfiles) {
             if (!profile->areAllDevicesSupported(devices) ||
-                    !profile->isCompatibleProfileForFlags(
-                            flags, false /*exactMatchRequiredForInputFlags*/)) {
+                    !profile->isCompatibleProfileForFlags(flags)) {
                 continue;
             }
             audioProfiles.addAllValidProfiles(profile->asAudioPort()->getAudioProfiles());
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index d83a277..e901cfd 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -1276,6 +1276,33 @@
     EXPECT_EQ(expectedChannelMask, requestedChannelMask);
 }
 
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, MatchesMoreInputFlagsWhenPossible) {
+    const audio_format_t expectedFormat = AUDIO_FORMAT_PCM_16_BIT;
+    const uint32_t expectedSampleRate = 48000;
+    const audio_channel_mask_t expectedChannelMask = AUDIO_CHANNEL_IN_STEREO;
+    const std::string expectedIOProfile = "mixport_fast_input";
+
+    auto devices = mManager->getAvailableInputDevices();
+    sp<DeviceDescriptor> mic = nullptr;
+    for (auto device : devices) {
+        if (device->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            mic = device;
+        break;
+        }
+    }
+    EXPECT_NE(nullptr, mic);
+
+    audio_format_t requestedFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+    uint32_t requestedSampleRate = 48000;
+    audio_channel_mask_t requestedChannelMask = AUDIO_CHANNEL_IN_STEREO;
+    auto profile = mManager->getInputProfile(
+            mic, requestedSampleRate, requestedFormat, requestedChannelMask, AUDIO_INPUT_FLAG_FAST);
+    EXPECT_EQ(expectedIOProfile, profile->getName());
+    EXPECT_EQ(expectedFormat, requestedFormat);
+    EXPECT_EQ(expectedSampleRate, requestedSampleRate);
+    EXPECT_EQ(expectedChannelMask, requestedChannelMask);
+}
+
 class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
 protected:
     void TearDown() override;
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index 3c64898..9cb3608 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -71,6 +71,11 @@
                              samplingRates="48000"
                              channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
                 </mixPort>
+                <mixPort name="mixport_fast_input" role="sink" flags="AUDIO_INPUT_FLAG_FAST">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                        samplingRates="48000"
+                        channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
             </mixPorts>
             <devicePorts>
                 <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
@@ -121,6 +126,8 @@
                         sources="USB Device In" />
                 <route type="mix" sink="multiple_channels_input"
                        sources="Built-In Mic" />
+                <route type="mix" sink="mixport_fast_input"
+                    sources="Built-In Mic"/>
             </routes>
         </module>