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 <media/AudioProductStrategy.h>
23 #include <media/TypeConverter.h>
24 #include <utils/String8.h>
25 #include <cstdint>
26 #include <string>
27
28 #include <log/log.h>
29
30
31 namespace android {
32
ProductStrategy(const std::string & name)33 ProductStrategy::ProductStrategy(const std::string &name) :
34 mName(name),
35 mId(static_cast<product_strategy_t>(HandleGenerator<uint32_t>::getNextHandle()))
36 {
37 }
38
addAttributes(const VolumeGroupAttributes & volumeGroupAttributes)39 void ProductStrategy::addAttributes(const VolumeGroupAttributes &volumeGroupAttributes)
40 {
41 mAttributesVector.push_back(volumeGroupAttributes);
42 }
43
listVolumeGroupAttributes() const44 std::vector<android::VolumeGroupAttributes> ProductStrategy::listVolumeGroupAttributes() const
45 {
46 std::vector<android::VolumeGroupAttributes> androidAa;
47 for (const auto &attr : mAttributesVector) {
48 androidAa.push_back({attr.getGroupId(), attr.getStreamType(), attr.getAttributes()});
49 }
50 return androidAa;
51 }
52
getAudioAttributes() const53 AttributesVector ProductStrategy::getAudioAttributes() const
54 {
55 AttributesVector attrVector;
56 for (const auto &attrGroup : mAttributesVector) {
57 attrVector.push_back(attrGroup.getAttributes());
58 }
59 if (not attrVector.empty()) {
60 return attrVector;
61 }
62 return { AUDIO_ATTRIBUTES_INITIALIZER };
63 }
64
matchesScore(const audio_attributes_t attr) const65 int ProductStrategy::matchesScore(const audio_attributes_t attr) const
66 {
67 int strategyScore = AudioProductStrategy::NO_MATCH;
68 for (const auto &attrGroup : mAttributesVector) {
69 int score = AudioProductStrategy::attributesMatchesScore(attrGroup.getAttributes(), attr);
70 if (score == AudioProductStrategy::MATCH_EQUALS) {
71 return score;
72 }
73 strategyScore = std::max(score, strategyScore);
74 }
75 return strategyScore;
76 }
77
getAttributesForStreamType(audio_stream_type_t streamType) const78 audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
79 {
80 const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
81 [&streamType](const auto &supportedAttr) {
82 return supportedAttr.getStreamType() == streamType; });
83 return iter != end(mAttributesVector) ? iter->getAttributes() : AUDIO_ATTRIBUTES_INITIALIZER;
84 }
85
isDefault() const86 bool ProductStrategy::isDefault() const
87 {
88 return std::find_if(begin(mAttributesVector), end(mAttributesVector), [](const auto &attr) {
89 return attr.getAttributes() == defaultAttr; }) != end(mAttributesVector);
90 }
91
getSupportedStreams() const92 StreamTypeVector ProductStrategy::getSupportedStreams() const
93 {
94 StreamTypeVector streams;
95 for (const auto &supportedAttr : mAttributesVector) {
96 if (std::find(begin(streams), end(streams), supportedAttr.getStreamType())
97 == end(streams) && supportedAttr.getStreamType() != AUDIO_STREAM_DEFAULT) {
98 streams.push_back(supportedAttr.getStreamType());
99 }
100 }
101 return streams;
102 }
103
supportStreamType(const audio_stream_type_t & streamType) const104 bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) const
105 {
106 return std::find_if(begin(mAttributesVector), end(mAttributesVector),
107 [&streamType](const auto &supportedAttr) {
108 return supportedAttr.getStreamType() == streamType; }) != end(mAttributesVector);
109 }
110
getVolumeGroupForStreamType(audio_stream_type_t stream) const111 volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
112 {
113 for (const auto &supportedAttr : mAttributesVector) {
114 if (supportedAttr.getStreamType() == stream) {
115 return supportedAttr.getGroupId();
116 }
117 }
118 return VOLUME_GROUP_NONE;
119 }
120
getDefaultVolumeGroup() const121 volume_group_t ProductStrategy::getDefaultVolumeGroup() const
122 {
123 const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
124 [](const auto &attr) {
125 return attr.getAttributes() == defaultAttr;
126 });
127 return iter != end(mAttributesVector) ? iter->getGroupId() : VOLUME_GROUP_NONE;
128 }
129
dump(String8 * dst,int spaces) const130 void ProductStrategy::dump(String8 *dst, int spaces) const
131 {
132 dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
133 std::string deviceLiteral = deviceTypesToString(mApplicableDevices);
134 dst->appendFormat("%*sSelected Device: {%s, @:%s}\n", spaces + 2, "",
135 deviceLiteral.c_str(), mDeviceAddress.c_str());
136
137 for (const auto &attr : mAttributesVector) {
138 dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.getGroupId(),
139 android::toString(attr.getStreamType()).c_str());
140 dst->appendFormat("%*s Attributes: ", spaces + 3, "");
141 std::string attStr = attr.getAttributes() == defaultAttr ?
142 "{ Any }" : android::toString(attr.getAttributes());
143 dst->appendFormat("%s\n", attStr.c_str());
144 }
145 }
146
getProductStrategyForAttributes(const audio_attributes_t & attributes,bool fallbackOnDefault) const147 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
148 const audio_attributes_t &attributes, bool fallbackOnDefault) const
149 {
150 product_strategy_t bestStrategyOrdefault = PRODUCT_STRATEGY_NONE;
151 int matchScore = AudioProductStrategy::NO_MATCH;
152 for (const auto &iter : *this) {
153 int score = iter.second->matchesScore(attributes);
154 if (score == AudioProductStrategy::MATCH_EQUALS) {
155 return iter.second->getId();
156 }
157 if (score > matchScore) {
158 bestStrategyOrdefault = iter.second->getId();
159 matchScore = score;
160 }
161 }
162 return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
163 bestStrategyOrdefault : PRODUCT_STRATEGY_NONE;
164 }
165
getAttributesForStreamType(audio_stream_type_t stream) const166 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
167 {
168 for (const auto &iter : *this) {
169 const auto strategy = iter.second;
170 if (strategy->supportStreamType(stream)) {
171 return strategy->getAttributesForStreamType(stream);
172 }
173 }
174 ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
175 toString(stream).c_str());
176 return {};
177 }
178
getDefault() const179 product_strategy_t ProductStrategyMap::getDefault() const
180 {
181 if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
182 return mDefaultStrategy;
183 }
184 for (const auto &iter : *this) {
185 if (iter.second->isDefault()) {
186 ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
187 return iter.second->getId();
188 }
189 }
190 ALOGE("%s: No default product strategy defined", __FUNCTION__);
191 return PRODUCT_STRATEGY_NONE;
192 }
193
getAttributesForProductStrategy(product_strategy_t strategy) const194 audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
195 product_strategy_t strategy) const
196 {
197 if (find(strategy) == end()) {
198 ALOGE("Invalid %d strategy requested", strategy);
199 return AUDIO_ATTRIBUTES_INITIALIZER;
200 }
201 return at(strategy)->getAudioAttributes()[0];
202 }
203
getProductStrategyForStream(audio_stream_type_t stream) const204 product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
205 {
206 for (const auto &iter : *this) {
207 if (iter.second->supportStreamType(stream)) {
208 return iter.second->getId();
209 }
210 }
211 ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
212 return getDefault();
213 }
214
215
getDeviceTypesForProductStrategy(product_strategy_t strategy) const216 DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
217 product_strategy_t strategy) const
218 {
219 if (find(strategy) == end()) {
220 ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
221 product_strategy_t defaultStrategy = getDefault();
222 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
223 return {AUDIO_DEVICE_NONE};
224 }
225 return at(getDefault())->getDeviceTypes();
226 }
227 return at(strategy)->getDeviceTypes();
228 }
229
getDeviceAddressForProductStrategy(product_strategy_t psId) const230 std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
231 {
232 if (find(psId) == end()) {
233 ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
234 product_strategy_t defaultStrategy = getDefault();
235 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
236 return {};
237 }
238 return at(getDefault())->getDeviceAddress();
239 }
240 return at(psId)->getDeviceAddress();
241 }
242
getVolumeGroupAttributesForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const243 VolumeGroupAttributes ProductStrategyMap::getVolumeGroupAttributesForAttributes(
244 const audio_attributes_t &attr, bool fallbackOnDefault) const
245 {
246 int matchScore = AudioProductStrategy::NO_MATCH;
247 VolumeGroupAttributes bestVolumeGroupAttributes = {};
248 for (const auto &iter : *this) {
249 for (const auto &volGroupAttr : iter.second->getVolumeGroupAttributes()) {
250 int score = volGroupAttr.matchesScore(attr);
251 if (score == AudioProductStrategy::MATCH_EQUALS) {
252 return volGroupAttr;
253 }
254 if (score > matchScore) {
255 matchScore = score;
256 bestVolumeGroupAttributes = volGroupAttr;
257 }
258 }
259 }
260 return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
261 bestVolumeGroupAttributes : VolumeGroupAttributes();
262 }
263
getStreamTypeForAttributes(const audio_attributes_t & attr) const264 audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
265 const audio_attributes_t &attr) const
266 {
267 audio_stream_type_t streamType = getVolumeGroupAttributesForAttributes(
268 attr, /* fallbackOnDefault= */ true).getStreamType();
269 return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
270 }
271
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const272 volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(
273 const audio_attributes_t &attr, bool fallbackOnDefault) const
274 {
275 return getVolumeGroupAttributesForAttributes(attr, fallbackOnDefault).getGroupId();
276 }
277
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const278 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(
279 audio_stream_type_t stream, bool fallbackOnDefault) const
280 {
281 for (const auto &iter : *this) {
282 volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
283 if (group != VOLUME_GROUP_NONE) {
284 return group;
285 }
286 }
287 ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
288 return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
289 }
290
getDefaultVolumeGroup() const291 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
292 {
293 product_strategy_t defaultStrategy = getDefault();
294 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
295 return VOLUME_GROUP_NONE;
296 }
297 return at(defaultStrategy)->getDefaultVolumeGroup();
298 }
299
initialize()300 void ProductStrategyMap::initialize()
301 {
302 mDefaultStrategy = getDefault();
303 ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
304 }
305
dump(String8 * dst,int spaces) const306 void ProductStrategyMap::dump(String8 *dst, int spaces) const
307 {
308 dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
309 for (const auto &iter : *this) {
310 iter.second->dump(dst, spaces + 2);
311 }
312 }
313
dumpProductStrategyDevicesRoleMap(const ProductStrategyDevicesRoleMap & productStrategyDeviceRoleMap,String8 * dst,int spaces)314 void dumpProductStrategyDevicesRoleMap(
315 const ProductStrategyDevicesRoleMap& productStrategyDeviceRoleMap,
316 String8 *dst,
317 int spaces) {
318 dst->appendFormat("\n%*sDevice role per product strategy dump:", spaces, "");
319 for (const auto& [strategyRolePair, devices] : productStrategyDeviceRoleMap) {
320 dst->appendFormat("\n%*sStrategy(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
321 strategyRolePair.first, strategyRolePair.second,
322 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
323 }
324 dst->appendFormat("\n");
325 }
326 }
327