[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;
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index e8251e3..1593be0 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -56,6 +56,7 @@
AttributesVector getAudioAttributes() const;
product_strategy_t getId() const { return mId; }
StreamTypeVector getSupportedStreams() const;
+ VolumeGroupAttributesVector getVolumeGroupAttributes() const { return mAttributesVector; }
/**
* @brief matches checks if the given audio attributes shall follow the strategy.
@@ -63,9 +64,9 @@
* If only the usage is available, the check is performed on the usages of the given
* attributes, otherwise all fields must match.
* @param attributes to consider
- * @return true if attributes matches with the strategy, false otherwise.
+ * @return matching score, negative value if no match.
*/
- bool matches(const audio_attributes_t attributes) const;
+ int matchesScore(const audio_attributes_t attributes) const;
bool supportStreamType(const audio_stream_type_t &streamType) const;
@@ -84,9 +85,6 @@
DeviceTypeSet getDeviceTypes() const { return mApplicableDevices; }
audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
- audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
-
- volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const;
volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const;
@@ -161,6 +159,9 @@
void dump(String8 *dst, int spaces = 0) const;
private:
+ VolumeGroupAttributes getVolumeGroupAttributesForAttributes(
+ const audio_attributes_t &attr, bool fallbackOnDefault = true) const;
+
product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE;
};
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index c104c97..1d3ad1c 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -62,29 +62,17 @@
return { AUDIO_ATTRIBUTES_INITIALIZER };
}
-bool ProductStrategy::matches(const audio_attributes_t attr) const
+int ProductStrategy::matchesScore(const audio_attributes_t attr) const
{
- return std::find_if(begin(mAttributesVector), end(mAttributesVector),
- [&attr](const auto &supportedAttr) {
- return AudioProductStrategy::attributesMatches(supportedAttr.getAttributes(), attr);
- }) != end(mAttributesVector);
-}
-
-audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(
- const audio_attributes_t &attr) const
-{
- const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
- [&attr](const auto &supportedAttr) {
- return AudioProductStrategy::attributesMatches(supportedAttr.getAttributes(), attr); });
- if (iter == end(mAttributesVector)) {
- return AUDIO_STREAM_DEFAULT;
+ int strategyScore = AudioProductStrategy::NO_MATCH;
+ for (const auto &attrGroup : mAttributesVector) {
+ int score = AudioProductStrategy::attributesMatchesScore(attrGroup.getAttributes(), attr);
+ if (score == AudioProductStrategy::MATCH_EQUALS) {
+ return score;
+ }
+ strategyScore = std::max(score, strategyScore);
}
- audio_stream_type_t streamType = iter->getStreamType();
- ALOGW_IF(streamType == AUDIO_STREAM_DEFAULT,
- "%s: Strategy %s supporting attributes %s has not stream type associated"
- "fallback on MUSIC. Do not use stream volume API", __func__, mName.c_str(),
- toString(attr).c_str());
- return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
+ return strategyScore;
}
audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
@@ -120,16 +108,6 @@
return supportedAttr.getStreamType() == streamType; }) != end(mAttributesVector);
}
-volume_group_t ProductStrategy::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
-{
- for (const auto &supportedAttr : mAttributesVector) {
- if (AudioProductStrategy::attributesMatches(supportedAttr.getAttributes(), attr)) {
- return supportedAttr.getGroupId();
- }
- }
- return VOLUME_GROUP_NONE;
-}
-
volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
{
for (const auto &supportedAttr : mAttributesVector) {
@@ -167,16 +145,22 @@
}
product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
- const audio_attributes_t &attr, bool fallbackOnDefault) const
+ const audio_attributes_t &attributes, bool fallbackOnDefault) const
{
+ product_strategy_t bestStrategyOrdefault = PRODUCT_STRATEGY_NONE;
+ int matchScore = AudioProductStrategy::NO_MATCH;
for (const auto &iter : *this) {
- if (iter.second->matches(attr)) {
+ int score = iter.second->matchesScore(attributes);
+ if (score == AudioProductStrategy::MATCH_EQUALS) {
return iter.second->getId();
}
+ if (score > matchScore) {
+ bestStrategyOrdefault = iter.second->getId();;
+ matchScore = score;
+ }
}
- ALOGV("%s: No matching product strategy for attributes %s, return default", __FUNCTION__,
- toString(attr).c_str());
- return fallbackOnDefault? getDefault() : PRODUCT_STRATEGY_NONE;
+ return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
+ bestStrategyOrdefault : PRODUCT_STRATEGY_NONE;
}
audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
@@ -192,20 +176,6 @@
return {};
}
-audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
- const audio_attributes_t &attr) const
-{
- for (const auto &iter : *this) {
- audio_stream_type_t stream = iter.second->getStreamTypeForAttributes(attr);
- if (stream != AUDIO_STREAM_DEFAULT) {
- return stream;
- }
- }
- ALOGV("%s: No product strategy for attributes %s, using default (aka MUSIC)", __FUNCTION__,
- toString(attr).c_str());
- return AUDIO_STREAM_MUSIC;
-}
-
product_strategy_t ProductStrategyMap::getDefault() const
{
if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
@@ -270,16 +240,39 @@
return at(psId)->getDeviceAddress();
}
+VolumeGroupAttributes ProductStrategyMap::getVolumeGroupAttributesForAttributes(
+ const audio_attributes_t &attr, bool fallbackOnDefault) const
+{
+ int matchScore = AudioProductStrategy::NO_MATCH;
+ VolumeGroupAttributes bestVolumeGroupAttributes = {};
+ for (const auto &iter : *this) {
+ for (const auto &volGroupAttr : iter.second->getVolumeGroupAttributes()) {
+ int score = volGroupAttr.matchesScore(attr);
+ if (score == AudioProductStrategy::MATCH_EQUALS) {
+ return volGroupAttr;
+ }
+ if (score > matchScore) {
+ matchScore = score;
+ bestVolumeGroupAttributes = volGroupAttr;
+ }
+ }
+ }
+ return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
+ bestVolumeGroupAttributes : VolumeGroupAttributes();
+}
+
+audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
+ const audio_attributes_t &attr) const
+{
+ audio_stream_type_t streamType = getVolumeGroupAttributesForAttributes(
+ attr, /* fallbackOnDefault= */ true).getStreamType();
+ return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
+}
+
volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(
const audio_attributes_t &attr, bool fallbackOnDefault) const
{
- for (const auto &iter : *this) {
- volume_group_t group = iter.second->getVolumeGroupForAttributes(attr);
- if (group != VOLUME_GROUP_NONE) {
- return group;
- }
- }
- return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
+ return getVolumeGroupAttributesForAttributes(attr, fallbackOnDefault).getGroupId();
}
volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(