xref: /aosp_15_r20/frameworks/av/services/audiopolicy/engine/common/src/ProductStrategy.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "APM::AudioPolicyEngine/ProductStrategy"
18 //#define LOG_NDEBUG 0
19 
20 #include "ProductStrategy.h"
21 
22 #include <android/media/audio/common/AudioHalProductStrategy.h>
23 #include <media/AudioProductStrategy.h>
24 #include <media/TypeConverter.h>
25 #include <utils/String8.h>
26 #include <cstdint>
27 #include <string>
28 
29 #include <log/log.h>
30 
31 
32 namespace android {
33 
34 using media::audio::common::AudioHalProductStrategy;
35 
36 /*
37  * Note on the id: either is provided (legacy strategies have hard coded id, aidl have
38  * own id, enforced to be started from VENDOR_STRATEGY_ID_START.
39  * REROUTING & PATCH system strategies are added.
40  * To prevent from collision, generate from VENDOR_STRATEGY_ID_START when id is not provided.
41  */
ProductStrategy(const std::string & name,int id)42 ProductStrategy::ProductStrategy(const std::string &name, int id) :
43     mName(name),
44     mId((static_cast<product_strategy_t>(id) != PRODUCT_STRATEGY_NONE) ?
45             static_cast<product_strategy_t>(id) :
46             static_cast<product_strategy_t>(AudioHalProductStrategy::VENDOR_STRATEGY_ID_START +
47                     HandleGenerator<uint32_t>::getNextHandle())) {}
48 
addAttributes(const VolumeGroupAttributes & volumeGroupAttributes)49 void ProductStrategy::addAttributes(const VolumeGroupAttributes &volumeGroupAttributes)
50 {
51     mAttributesVector.push_back(volumeGroupAttributes);
52 }
53 
listVolumeGroupAttributes() const54 std::vector<android::VolumeGroupAttributes> ProductStrategy::listVolumeGroupAttributes() const
55 {
56     std::vector<android::VolumeGroupAttributes> androidAa;
57     for (const auto &attr : mAttributesVector) {
58         androidAa.push_back({attr.getGroupId(), attr.getStreamType(), attr.getAttributes()});
59     }
60     return androidAa;
61 }
62 
getAudioAttributes() const63 AttributesVector ProductStrategy::getAudioAttributes() const
64 {
65     AttributesVector attrVector;
66     for (const auto &attrGroup : mAttributesVector) {
67         attrVector.push_back(attrGroup.getAttributes());
68     }
69     if (not attrVector.empty()) {
70         return attrVector;
71     }
72     return { AUDIO_ATTRIBUTES_INITIALIZER };
73 }
74 
matchesScore(const audio_attributes_t attr) const75 int ProductStrategy::matchesScore(const audio_attributes_t attr) const
76 {
77     int strategyScore = AudioProductStrategy::NO_MATCH;
78     for (const auto &attrGroup : mAttributesVector) {
79         int score = AudioProductStrategy::attributesMatchesScore(attrGroup.getAttributes(), attr);
80         if (score == AudioProductStrategy::MATCH_EQUALS) {
81             return score;
82         }
83         strategyScore = std::max(score, strategyScore);
84     }
85     return strategyScore;
86 }
87 
getAttributesForStreamType(audio_stream_type_t streamType) const88 audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
89 {
90     const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
91                                    [&streamType](const auto &supportedAttr) {
92         return supportedAttr.getStreamType() == streamType; });
93     return iter != end(mAttributesVector) ? iter->getAttributes() : AUDIO_ATTRIBUTES_INITIALIZER;
94 }
95 
isDefault() const96 bool ProductStrategy::isDefault() const
97 {
98     return std::find_if(begin(mAttributesVector), end(mAttributesVector), [](const auto &attr) {
99         return attr.getAttributes() == defaultAttr; }) != end(mAttributesVector);
100 }
101 
getSupportedStreams() const102 StreamTypeVector ProductStrategy::getSupportedStreams() const
103 {
104     StreamTypeVector streams;
105     for (const auto &supportedAttr : mAttributesVector) {
106         if (std::find(begin(streams), end(streams), supportedAttr.getStreamType())
107                 == end(streams) && supportedAttr.getStreamType() != AUDIO_STREAM_DEFAULT) {
108             streams.push_back(supportedAttr.getStreamType());
109         }
110     }
111     return streams;
112 }
113 
supportStreamType(const audio_stream_type_t & streamType) const114 bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) const
115 {
116     return std::find_if(begin(mAttributesVector), end(mAttributesVector),
117                         [&streamType](const auto &supportedAttr) {
118         return supportedAttr.getStreamType() == streamType; }) != end(mAttributesVector);
119 }
120 
getVolumeGroupForStreamType(audio_stream_type_t stream) const121 volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
122 {
123     for (const auto &supportedAttr : mAttributesVector) {
124         if (supportedAttr.getStreamType() == stream) {
125             return supportedAttr.getGroupId();
126         }
127     }
128     return VOLUME_GROUP_NONE;
129 }
130 
getDefaultVolumeGroup() const131 volume_group_t ProductStrategy::getDefaultVolumeGroup() const
132 {
133     const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
134                                     [](const auto &attr) {
135         return attr.getAttributes() == defaultAttr;
136     });
137     return iter != end(mAttributesVector) ? iter->getGroupId() : VOLUME_GROUP_NONE;
138 }
139 
dump(String8 * dst,int spaces) const140 void ProductStrategy::dump(String8 *dst, int spaces) const
141 {
142     dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
143     std::string deviceLiteral = deviceTypesToString(mApplicableDevices);
144     dst->appendFormat("%*sSelected Device: {%s, @:%s}\n", spaces + 2, "",
145                        deviceLiteral.c_str(), mDeviceAddress.c_str());
146 
147     for (const auto &attr : mAttributesVector) {
148         dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.getGroupId(),
149                           android::toString(attr.getStreamType()).c_str());
150         dst->appendFormat("%*s Attributes: ", spaces + 3, "");
151         std::string attStr = attr.getAttributes() == defaultAttr ?
152                 "{ Any }" : android::toString(attr.getAttributes());
153         dst->appendFormat("%s\n", attStr.c_str());
154     }
155 }
156 
getProductStrategyForAttributes(const audio_attributes_t & attributes,bool fallbackOnDefault) const157 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
158         const audio_attributes_t &attributes, bool fallbackOnDefault) const
159 {
160     product_strategy_t bestStrategyOrdefault = PRODUCT_STRATEGY_NONE;
161     int matchScore = AudioProductStrategy::NO_MATCH;
162     for (const auto &iter : *this) {
163         int score = iter.second->matchesScore(attributes);
164         if (score == AudioProductStrategy::MATCH_EQUALS) {
165             return iter.second->getId();
166         }
167         if (score > matchScore) {
168             bestStrategyOrdefault = iter.second->getId();
169             matchScore = score;
170         }
171     }
172     return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
173             bestStrategyOrdefault : PRODUCT_STRATEGY_NONE;
174 }
175 
getAttributesForStreamType(audio_stream_type_t stream) const176 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
177 {
178     for (const auto &iter : *this) {
179         const auto strategy = iter.second;
180         if (strategy->supportStreamType(stream)) {
181             return strategy->getAttributesForStreamType(stream);
182         }
183     }
184     ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
185           toString(stream).c_str());
186     return {};
187 }
188 
getDefault() const189 product_strategy_t ProductStrategyMap::getDefault() const
190 {
191     if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
192         return mDefaultStrategy;
193     }
194     for (const auto &iter : *this) {
195         if (iter.second->isDefault()) {
196             ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
197             return iter.second->getId();
198         }
199     }
200     ALOGE("%s: No default product strategy defined", __FUNCTION__);
201     return PRODUCT_STRATEGY_NONE;
202 }
203 
getAttributesForProductStrategy(product_strategy_t strategy) const204 audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
205         product_strategy_t strategy) const
206 {
207     if (find(strategy) == end()) {
208         ALOGE("Invalid %d strategy requested", strategy);
209         return AUDIO_ATTRIBUTES_INITIALIZER;
210     }
211     return at(strategy)->getAudioAttributes()[0];
212 }
213 
getProductStrategyForStream(audio_stream_type_t stream) const214 product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
215 {
216     for (const auto &iter : *this) {
217         if (iter.second->supportStreamType(stream)) {
218             return iter.second->getId();
219         }
220     }
221     ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
222     return getDefault();
223 }
224 
225 
getDeviceTypesForProductStrategy(product_strategy_t strategy) const226 DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
227         product_strategy_t strategy) const
228 {
229     if (find(strategy) == end()) {
230         ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
231         product_strategy_t defaultStrategy = getDefault();
232         if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
233             return {AUDIO_DEVICE_NONE};
234         }
235         return at(getDefault())->getDeviceTypes();
236     }
237     return at(strategy)->getDeviceTypes();
238 }
239 
getDeviceAddressForProductStrategy(product_strategy_t psId) const240 std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
241 {
242     if (find(psId) == end()) {
243         ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
244         product_strategy_t defaultStrategy = getDefault();
245         if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
246             return {};
247         }
248         return at(getDefault())->getDeviceAddress();
249     }
250     return at(psId)->getDeviceAddress();
251 }
252 
getVolumeGroupAttributesForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const253 VolumeGroupAttributes ProductStrategyMap::getVolumeGroupAttributesForAttributes(
254         const audio_attributes_t &attr, bool fallbackOnDefault) const
255 {
256     int matchScore = AudioProductStrategy::NO_MATCH;
257     VolumeGroupAttributes bestVolumeGroupAttributes = {};
258     for (const auto &iter : *this) {
259         for (const auto &volGroupAttr : iter.second->getVolumeGroupAttributes()) {
260             int score = volGroupAttr.matchesScore(attr);
261             if (score == AudioProductStrategy::MATCH_EQUALS) {
262                 return volGroupAttr;
263             }
264             if (score > matchScore) {
265                 matchScore = score;
266                 bestVolumeGroupAttributes = volGroupAttr;
267             }
268         }
269     }
270     return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
271             bestVolumeGroupAttributes : VolumeGroupAttributes();
272 }
273 
getStreamTypeForAttributes(const audio_attributes_t & attr) const274 audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
275         const audio_attributes_t &attr) const
276 {
277     audio_stream_type_t streamType = getVolumeGroupAttributesForAttributes(
278             attr, /* fallbackOnDefault= */ true).getStreamType();
279     return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
280 }
281 
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const282 volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(
283         const audio_attributes_t &attr, bool fallbackOnDefault) const
284 {
285     return getVolumeGroupAttributesForAttributes(attr, fallbackOnDefault).getGroupId();
286 }
287 
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const288 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(
289         audio_stream_type_t stream, bool fallbackOnDefault) const
290 {
291     for (const auto &iter : *this) {
292         volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
293         if (group != VOLUME_GROUP_NONE) {
294             return group;
295         }
296     }
297     ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
298     return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
299 }
300 
getDefaultVolumeGroup() const301 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
302 {
303     product_strategy_t defaultStrategy = getDefault();
304     if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
305         return VOLUME_GROUP_NONE;
306     }
307     return at(defaultStrategy)->getDefaultVolumeGroup();
308 }
309 
initialize()310 void ProductStrategyMap::initialize()
311 {
312     mDefaultStrategy = getDefault();
313     ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
314 }
315 
dump(String8 * dst,int spaces) const316 void ProductStrategyMap::dump(String8 *dst, int spaces) const
317 {
318     dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
319     for (const auto &iter : *this) {
320         iter.second->dump(dst, spaces + 2);
321     }
322 }
323 
dumpProductStrategyDevicesRoleMap(const ProductStrategyDevicesRoleMap & productStrategyDeviceRoleMap,String8 * dst,int spaces)324 void dumpProductStrategyDevicesRoleMap(
325         const ProductStrategyDevicesRoleMap& productStrategyDeviceRoleMap,
326         String8 *dst,
327         int spaces) {
328     dst->appendFormat("\n%*sDevice role per product strategy dump:", spaces, "");
329     for (const auto& [strategyRolePair, devices] : productStrategyDeviceRoleMap) {
330         dst->appendFormat("\n%*sStrategy(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
331                 strategyRolePair.first, strategyRolePair.second,
332                 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
333     }
334     dst->appendFormat("\n");
335 }
336 }
337