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 AudioAttributes & audioAttributes)39 void ProductStrategy::addAttributes(const AudioAttributes &audioAttributes)
40 {
41 mAttributesVector.push_back(audioAttributes);
42 }
43
listAudioAttributes() const44 std::vector<android::AudioAttributes> ProductStrategy::listAudioAttributes() const
45 {
46 std::vector<android::AudioAttributes> androidAa;
47 for (const auto &attr : mAttributesVector) {
48 androidAa.push_back({attr.mVolumeGroup, attr.mStream, attr.mAttributes});
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.mAttributes);
58 }
59 if (not attrVector.empty()) {
60 return attrVector;
61 }
62 return { AUDIO_ATTRIBUTES_INITIALIZER };
63 }
64
matches(const audio_attributes_t attr) const65 bool ProductStrategy::matches(const audio_attributes_t attr) const
66 {
67 return std::find_if(begin(mAttributesVector), end(mAttributesVector),
68 [&attr](const auto &supportedAttr) {
69 return AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr);
70 }) != end(mAttributesVector);
71 }
72
getStreamTypeForAttributes(const audio_attributes_t & attr) const73 audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(
74 const audio_attributes_t &attr) const
75 {
76 const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
77 [&attr](const auto &supportedAttr) {
78 return AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr); });
79 if (iter == end(mAttributesVector)) {
80 return AUDIO_STREAM_DEFAULT;
81 }
82 audio_stream_type_t streamType = iter->mStream;
83 ALOGW_IF(streamType == AUDIO_STREAM_DEFAULT,
84 "%s: Strategy %s supporting attributes %s has not stream type associated"
85 "fallback on MUSIC. Do not use stream volume API", __func__, mName.c_str(),
86 toString(attr).c_str());
87 return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
88 }
89
getAttributesForStreamType(audio_stream_type_t streamType) const90 audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
91 {
92 const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
93 [&streamType](const auto &supportedAttr) {
94 return supportedAttr.mStream == streamType; });
95 return iter != end(mAttributesVector) ? iter->mAttributes : AUDIO_ATTRIBUTES_INITIALIZER;
96 }
97
isDefault() const98 bool ProductStrategy::isDefault() const
99 {
100 return std::find_if(begin(mAttributesVector), end(mAttributesVector), [](const auto &attr) {
101 return attr.mAttributes == defaultAttr; }) != end(mAttributesVector);
102 }
103
getSupportedStreams() const104 StreamTypeVector ProductStrategy::getSupportedStreams() const
105 {
106 StreamTypeVector streams;
107 for (const auto &supportedAttr : mAttributesVector) {
108 if (std::find(begin(streams), end(streams), supportedAttr.mStream) == end(streams) &&
109 supportedAttr.mStream != AUDIO_STREAM_DEFAULT) {
110 streams.push_back(supportedAttr.mStream);
111 }
112 }
113 return streams;
114 }
115
supportStreamType(const audio_stream_type_t & streamType) const116 bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) const
117 {
118 return std::find_if(begin(mAttributesVector), end(mAttributesVector),
119 [&streamType](const auto &supportedAttr) {
120 return supportedAttr.mStream == streamType; }) != end(mAttributesVector);
121 }
122
getVolumeGroupForAttributes(const audio_attributes_t & attr) const123 volume_group_t ProductStrategy::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
124 {
125 for (const auto &supportedAttr : mAttributesVector) {
126 if (AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr)) {
127 return supportedAttr.mVolumeGroup;
128 }
129 }
130 return VOLUME_GROUP_NONE;
131 }
132
getVolumeGroupForStreamType(audio_stream_type_t stream) const133 volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
134 {
135 for (const auto &supportedAttr : mAttributesVector) {
136 if (supportedAttr.mStream == stream) {
137 return supportedAttr.mVolumeGroup;
138 }
139 }
140 return VOLUME_GROUP_NONE;
141 }
142
getDefaultVolumeGroup() const143 volume_group_t ProductStrategy::getDefaultVolumeGroup() const
144 {
145 const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
146 [](const auto &attr) {return attr.mAttributes == defaultAttr;});
147 return iter != end(mAttributesVector) ? iter->mVolumeGroup : VOLUME_GROUP_NONE;
148 }
149
dump(String8 * dst,int spaces) const150 void ProductStrategy::dump(String8 *dst, int spaces) const
151 {
152 dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
153 std::string deviceLiteral;
154 if (!deviceTypesToString(mApplicableDevices, deviceLiteral)) {
155 ALOGE("%s: failed to convert device %s",
156 __FUNCTION__, dumpDeviceTypes(mApplicableDevices).c_str());
157 }
158 dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
159 deviceLiteral.c_str(), mDeviceAddress.c_str());
160
161 for (const auto &attr : mAttributesVector) {
162 dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mVolumeGroup,
163 android::toString(attr.mStream).c_str());
164 dst->appendFormat("%*s Attributes: ", spaces + 3, "");
165 std::string attStr =
166 attr.mAttributes == defaultAttr ? "{ Any }" : android::toString(attr.mAttributes);
167 dst->appendFormat("%s\n", attStr.c_str());
168 }
169 }
170
getProductStrategyForAttributes(const audio_attributes_t & attr) const171 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
172 const audio_attributes_t &attr) const
173 {
174 for (const auto &iter : *this) {
175 if (iter.second->matches(attr)) {
176 return iter.second->getId();
177 }
178 }
179 ALOGV("%s: No matching product strategy for attributes %s, return default", __FUNCTION__,
180 toString(attr).c_str());
181 return getDefault();
182 }
183
getAttributesForStreamType(audio_stream_type_t stream) const184 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
185 {
186 for (const auto &iter : *this) {
187 const auto strategy = iter.second;
188 if (strategy->supportStreamType(stream)) {
189 return strategy->getAttributesForStreamType(stream);
190 }
191 }
192 ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
193 toString(stream).c_str());
194 return {};
195 }
196
getStreamTypeForAttributes(const audio_attributes_t & attr) const197 audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
198 const audio_attributes_t &attr) const
199 {
200 for (const auto &iter : *this) {
201 audio_stream_type_t stream = iter.second->getStreamTypeForAttributes(attr);
202 if (stream != AUDIO_STREAM_DEFAULT) {
203 return stream;
204 }
205 }
206 ALOGV("%s: No product strategy for attributes %s, using default (aka MUSIC)", __FUNCTION__,
207 toString(attr).c_str());
208 return AUDIO_STREAM_MUSIC;
209 }
210
getDefault() const211 product_strategy_t ProductStrategyMap::getDefault() const
212 {
213 if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
214 return mDefaultStrategy;
215 }
216 for (const auto &iter : *this) {
217 if (iter.second->isDefault()) {
218 ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
219 return iter.second->getId();
220 }
221 }
222 ALOGE("%s: No default product strategy defined", __FUNCTION__);
223 return PRODUCT_STRATEGY_NONE;
224 }
225
getAttributesForProductStrategy(product_strategy_t strategy) const226 audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
227 product_strategy_t strategy) const
228 {
229 if (find(strategy) == end()) {
230 ALOGE("Invalid %d strategy requested", strategy);
231 return AUDIO_ATTRIBUTES_INITIALIZER;
232 }
233 return at(strategy)->getAudioAttributes()[0];
234 }
235
getProductStrategyForStream(audio_stream_type_t stream) const236 product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
237 {
238 for (const auto &iter : *this) {
239 if (iter.second->supportStreamType(stream)) {
240 return iter.second->getId();
241 }
242 }
243 ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
244 return getDefault();
245 }
246
247
getDeviceTypesForProductStrategy(product_strategy_t strategy) const248 DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
249 product_strategy_t strategy) const
250 {
251 if (find(strategy) == end()) {
252 ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
253 product_strategy_t defaultStrategy = getDefault();
254 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
255 return {AUDIO_DEVICE_NONE};
256 }
257 return at(getDefault())->getDeviceTypes();
258 }
259 return at(strategy)->getDeviceTypes();
260 }
261
getDeviceAddressForProductStrategy(product_strategy_t psId) const262 std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
263 {
264 if (find(psId) == end()) {
265 ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
266 product_strategy_t defaultStrategy = getDefault();
267 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
268 return {};
269 }
270 return at(getDefault())->getDeviceAddress();
271 }
272 return at(psId)->getDeviceAddress();
273 }
274
getVolumeGroupForAttributes(const audio_attributes_t & attr) const275 volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
276 {
277 for (const auto &iter : *this) {
278 volume_group_t group = iter.second->getVolumeGroupForAttributes(attr);
279 if (group != VOLUME_GROUP_NONE) {
280 return group;
281 }
282 }
283 return getDefaultVolumeGroup();
284 }
285
getVolumeGroupForStreamType(audio_stream_type_t stream) const286 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const
287 {
288 for (const auto &iter : *this) {
289 volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
290 if (group != VOLUME_GROUP_NONE) {
291 return group;
292 }
293 }
294 ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
295 return getDefaultVolumeGroup();
296 }
297
getDefaultVolumeGroup() const298 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
299 {
300 product_strategy_t defaultStrategy = getDefault();
301 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
302 return VOLUME_GROUP_NONE;
303 }
304 return at(defaultStrategy)->getDefaultVolumeGroup();
305 }
306
initialize()307 void ProductStrategyMap::initialize()
308 {
309 mDefaultStrategy = getDefault();
310 ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
311 }
312
dump(String8 * dst,int spaces) const313 void ProductStrategyMap::dump(String8 *dst, int spaces) const
314 {
315 dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
316 for (const auto &iter : *this) {
317 iter.second->dump(dst, spaces + 2);
318 }
319 }
320
dump(android::String8 * dst,int spaces) const321 void ProductStrategyPreferredRoutingMap::dump(android::String8* dst, int spaces) const {
322 dst->appendFormat("\n%*sPreferred devices per product strategy dump:", spaces, "");
323 for (const auto& iter : *this) {
324 dst->appendFormat("\n%*sStrategy %u dev:%08x addr:%s",
325 spaces + 2, "",
326 (uint32_t) iter.first,
327 iter.second.mType, iter.second.mAddress.c_str());
328 }
329 dst->appendFormat("\n");
330 }
331 }
332
333