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