[AOSP_IMPR] AudioPolicy: engine: add matching score API

Bug: 260298113
Test: build

Change-Id: I72ff69abc09d8017564bf8f811b5586aab9ebdec
Signed-off-by: François Gaffie <francois.gaffie@renault.com>
diff --git a/media/libaudioclient/AudioProductStrategy.cpp b/media/libaudioclient/AudioProductStrategy.cpp
index 381faf6..d9fd58c 100644
--- a/media/libaudioclient/AudioProductStrategy.cpp
+++ b/media/libaudioclient/AudioProductStrategy.cpp
@@ -60,25 +60,50 @@
 }
 
 // Keep in sync with android/media/audiopolicy/AudioProductStrategy#attributeMatches
-bool AudioProductStrategy::attributesMatches(const audio_attributes_t refAttributes,
-                                        const audio_attributes_t clientAttritubes)
+int AudioProductStrategy::attributesMatchesScore(const audio_attributes_t refAttributes,
+                                                 const audio_attributes_t clientAttritubes)
 {
+    if (refAttributes == clientAttritubes) {
+        return MATCH_EQUALS;
+    }
     if (refAttributes == AUDIO_ATTRIBUTES_INITIALIZER) {
         // The default product strategy is the strategy that holds default attributes by convention.
         // All attributes that fail to match will follow the default strategy for routing.
-        // Choosing the default must be done as a fallback, the attributes match shall not
-        // select the default.
-        return false;
+        // Choosing the default must be done as a fallback,so return a default (zero) score to
+        // allow identify the fallback.
+        return MATCH_ON_DEFAULT_SCORE;
     }
-    return ((refAttributes.usage == AUDIO_USAGE_UNKNOWN) ||
-            (clientAttritubes.usage == refAttributes.usage)) &&
-            ((refAttributes.content_type == AUDIO_CONTENT_TYPE_UNKNOWN) ||
-             (clientAttritubes.content_type == refAttributes.content_type)) &&
-            ((refAttributes.flags == AUDIO_FLAG_NONE) ||
-             (clientAttritubes.flags != AUDIO_FLAG_NONE &&
-            (clientAttritubes.flags & refAttributes.flags) == refAttributes.flags)) &&
-            ((strlen(refAttributes.tags) == 0) ||
-             (std::strcmp(clientAttritubes.tags, refAttributes.tags) == 0));
+    int score = MATCH_ON_DEFAULT_SCORE;
+    if (refAttributes.usage == AUDIO_USAGE_UNKNOWN) {
+        score |= MATCH_ON_DEFAULT_SCORE;
+    } else if (clientAttritubes.usage == refAttributes.usage) {
+        score |= MATCH_ON_USAGE_SCORE;
+    } else {
+        return NO_MATCH;
+    }
+    if (refAttributes.content_type == AUDIO_CONTENT_TYPE_UNKNOWN) {
+        score |= MATCH_ON_DEFAULT_SCORE;
+    } else if (clientAttritubes.content_type == refAttributes.content_type) {
+        score |= MATCH_ON_CONTENT_TYPE_SCORE;
+    } else {
+        return NO_MATCH;
+    }
+    if (strlen(refAttributes.tags) == 0) {
+        score |= MATCH_ON_DEFAULT_SCORE;
+    } else if (std::strcmp(clientAttritubes.tags, refAttributes.tags) == 0) {
+        score |= MATCH_ON_TAGS_SCORE;
+    } else {
+        return NO_MATCH;
+    }
+    if (refAttributes.flags == AUDIO_FLAG_NONE) {
+        score |= MATCH_ON_DEFAULT_SCORE;
+    } else if ((clientAttritubes.flags != AUDIO_FLAG_NONE)
+            && ((clientAttritubes.flags & refAttributes.flags) == refAttributes.flags)) {
+        score |= MATCH_ON_FLAGS_SCORE;
+    } else {
+        return NO_MATCH;
+    }
+    return score;
 }
 
 } // namespace android
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 706f51f..28d76d7 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -2136,8 +2136,7 @@
         if (strategy.getId() == psId) {
             auto attrVect = strategy.getVolumeGroupAttributes();
             auto iter = std::find_if(begin(attrVect), end(attrVect), [&attr](const auto& refAttr) {
-                return AudioProductStrategy::attributesMatches(
-                        refAttr.getAttributes(), attr);
+                return refAttr.matchesScore(attr) > 0;
             });
             if (iter != end(attrVect)) {
                 return iter->getStreamType();
diff --git a/media/libaudioclient/VolumeGroupAttributes.cpp b/media/libaudioclient/VolumeGroupAttributes.cpp
index 2de4667..530e73f 100644
--- a/media/libaudioclient/VolumeGroupAttributes.cpp
+++ b/media/libaudioclient/VolumeGroupAttributes.cpp
@@ -21,11 +21,16 @@
 #include <binder/Parcel.h>
 
 #include <media/AidlConversion.h>
+#include <media/AudioProductStrategy.h>
 #include <media/VolumeGroupAttributes.h>
 #include <media/PolicyAidlConversion.h>
 
 namespace android {
 
+int VolumeGroupAttributes::matchesScore(const audio_attributes_t &attributes) const {
+    return AudioProductStrategy::attributesMatchesScore(mAttributes, attributes);
+}
+
 status_t VolumeGroupAttributes::readFromParcel(const Parcel* parcel) {
     media::AudioAttributesEx aidl;
     RETURN_STATUS_IF_ERROR(aidl.readFromParcel(parcel));
diff --git a/media/libaudioclient/include/media/AudioProductStrategy.h b/media/libaudioclient/include/media/AudioProductStrategy.h
index 7bcb5aa..fcbb019 100644
--- a/media/libaudioclient/include/media/AudioProductStrategy.h
+++ b/media/libaudioclient/include/media/AudioProductStrategy.h
@@ -46,19 +46,35 @@
     status_t writeToParcel(Parcel *parcel) const override;
 
     /**
-     * @brief attributesMatches: checks if client attributes matches with a reference attributes
-     * "matching" means the usage shall match if reference attributes has a defined usage, AND
-     * content type shall match if reference attributes has a defined content type AND
+     * @brief attributesMatchesScore: checks if client attributes matches with a reference
+     * attributes "matching" means the usage shall match if reference attributes has a defined
+     * usage, AND content type shall match if reference attributes has a defined content type AND
      * flags shall match if reference attributes has defined flags AND
      * tags shall match if reference attributes has defined tags.
-     * Reference attributes "default" shall not be considered as a "true" case. This convention
+     * Reference attributes "default" shall be considered as a weak match case. This convention
      * is used to identify the default strategy.
      * @param refAttributes to be considered
      * @param clientAttritubes to be considered
-     * @return true if matching, false otherwise
+     * @return {@code INVALID_SCORE} if not matching, {@code MATCH_ON_DEFAULT_SCORE} if matching
+     * to default strategy, non zero positive score if matching a strategy.
      */
+    static int attributesMatchesScore(const audio_attributes_t refAttributes,
+                                      const audio_attributes_t clientAttritubes);
+
     static bool attributesMatches(const audio_attributes_t refAttributes,
-                                  const audio_attributes_t clientAttritubes);
+                                      const audio_attributes_t clientAttritubes) {
+        return attributesMatchesScore(refAttributes, clientAttritubes) > 0;
+    }
+
+    static const int MATCH_ON_TAGS_SCORE = 1 << 3;
+    static const int MATCH_ON_FLAGS_SCORE = 1 << 2;
+    static const int MATCH_ON_USAGE_SCORE = 1 << 1;
+    static const int MATCH_ON_CONTENT_TYPE_SCORE = 1 << 0;
+    static const int MATCH_ON_DEFAULT_SCORE = 0;
+    static const int MATCH_EQUALS = MATCH_ON_TAGS_SCORE | MATCH_ON_FLAGS_SCORE
+            | MATCH_ON_USAGE_SCORE | MATCH_ON_CONTENT_TYPE_SCORE;
+    static const int NO_MATCH = -1;
+
 private:
     std::string mName;
     std::vector<VolumeGroupAttributes> mVolumeGroupAttributes;
diff --git a/media/libaudioclient/include/media/VolumeGroupAttributes.h b/media/libaudioclient/include/media/VolumeGroupAttributes.h
index 0859995..46b3612 100644
--- a/media/libaudioclient/include/media/VolumeGroupAttributes.h
+++ b/media/libaudioclient/include/media/VolumeGroupAttributes.h
@@ -41,6 +41,8 @@
         mAttributes.source = AUDIO_SOURCE_INVALID;
     }
 
+    int matchesScore(const audio_attributes_t &attributes) const;
+
     audio_attributes_t getAttributes() const { return mAttributes; }
 
     status_t readFromParcel(const Parcel *parcel) override;