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/TypeConverter.h>
23 #include <utils/String8.h>
24 #include <cstdint>
25 #include <string>
26
27 #include <log/log.h>
28
29
30 namespace android {
31
ProductStrategy(const std::string & name)32 ProductStrategy::ProductStrategy(const std::string &name) :
33 mName(name),
34 mId(static_cast<product_strategy_t>(HandleGenerator<uint32_t>::getNextHandle()))
35 {
36 }
37
addAttributes(const AudioAttributes & audioAttributes)38 void ProductStrategy::addAttributes(const AudioAttributes &audioAttributes)
39 {
40 mAttributesVector.push_back(audioAttributes);
41 }
42
listAudioAttributes() const43 std::vector<android::AudioAttributes> ProductStrategy::listAudioAttributes() const
44 {
45 std::vector<android::AudioAttributes> androidAa;
46 for (const auto &attr : mAttributesVector) {
47 androidAa.push_back({attr.mVolumeGroup, attr.mStream, attr.mAttributes});
48 }
49 return androidAa;
50 }
51
getAudioAttributes() const52 AttributesVector ProductStrategy::getAudioAttributes() const
53 {
54 AttributesVector attrVector;
55 for (const auto &attrGroup : mAttributesVector) {
56 attrVector.push_back(attrGroup.mAttributes);
57 }
58 if (not attrVector.empty()) {
59 return attrVector;
60 }
61 return { AUDIO_ATTRIBUTES_INITIALIZER };
62 }
63
matches(const audio_attributes_t attr) const64 bool ProductStrategy::matches(const audio_attributes_t attr) const
65 {
66 return std::find_if(begin(mAttributesVector), end(mAttributesVector),
67 [&attr](const auto &supportedAttr) {
68 return AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr);
69 }) != end(mAttributesVector);
70 }
71
getStreamTypeForAttributes(const audio_attributes_t & attr) const72 audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(
73 const audio_attributes_t &attr) const
74 {
75 const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
76 [&attr](const auto &supportedAttr) {
77 return AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr); });
78 return iter != end(mAttributesVector) ? iter->mStream : AUDIO_STREAM_DEFAULT;
79 }
80
getAttributesForStreamType(audio_stream_type_t streamType) const81 audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
82 {
83 const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
84 [&streamType](const auto &supportedAttr) {
85 return supportedAttr.mStream == streamType; });
86 return iter != end(mAttributesVector) ? iter->mAttributes : AUDIO_ATTRIBUTES_INITIALIZER;
87 }
88
isDefault() const89 bool ProductStrategy::isDefault() const
90 {
91 return std::find_if(begin(mAttributesVector), end(mAttributesVector), [](const auto &attr) {
92 return attr.mAttributes == defaultAttr; }) != end(mAttributesVector);
93 }
94
getSupportedStreams() const95 StreamTypeVector ProductStrategy::getSupportedStreams() const
96 {
97 StreamTypeVector streams;
98 for (const auto &supportedAttr : mAttributesVector) {
99 if (std::find(begin(streams), end(streams), supportedAttr.mStream) == end(streams) &&
100 supportedAttr.mStream != AUDIO_STREAM_DEFAULT) {
101 streams.push_back(supportedAttr.mStream);
102 }
103 }
104 return streams;
105 }
106
supportStreamType(const audio_stream_type_t & streamType) const107 bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) const
108 {
109 return std::find_if(begin(mAttributesVector), end(mAttributesVector),
110 [&streamType](const auto &supportedAttr) {
111 return supportedAttr.mStream == streamType; }) != end(mAttributesVector);
112 }
113
getVolumeGroupForAttributes(const audio_attributes_t & attr) const114 volume_group_t ProductStrategy::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
115 {
116 for (const auto &supportedAttr : mAttributesVector) {
117 if (AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr)) {
118 return supportedAttr.mVolumeGroup;
119 }
120 }
121 return VOLUME_GROUP_NONE;
122 }
123
getVolumeGroupForStreamType(audio_stream_type_t stream) const124 volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
125 {
126 for (const auto &supportedAttr : mAttributesVector) {
127 if (supportedAttr.mStream == stream) {
128 return supportedAttr.mVolumeGroup;
129 }
130 }
131 return VOLUME_GROUP_NONE;
132 }
133
getDefaultVolumeGroup() const134 volume_group_t ProductStrategy::getDefaultVolumeGroup() const
135 {
136 const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
137 [](const auto &attr) {return attr.mAttributes == defaultAttr;});
138 return iter != end(mAttributesVector) ? iter->mVolumeGroup : VOLUME_GROUP_NONE;
139 }
140
dump(String8 * dst,int spaces) const141 void ProductStrategy::dump(String8 *dst, int spaces) const
142 {
143 dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
144 std::string deviceLiteral;
145 if (!OutputDeviceConverter::toString(mApplicableDevices, deviceLiteral)) {
146 ALOGE("%s: failed to convert device %d", __FUNCTION__, mApplicableDevices);
147 }
148 dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
149 deviceLiteral.c_str(), mDeviceAddress.c_str());
150
151 for (const auto &attr : mAttributesVector) {
152 dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mVolumeGroup,
153 android::toString(attr.mStream).c_str());
154 dst->appendFormat("%*s Attributes: ", spaces + 3, "");
155 std::string attStr =
156 attr.mAttributes == defaultAttr ? "{ Any }" : android::toString(attr.mAttributes);
157 dst->appendFormat("%s\n", attStr.c_str());
158 }
159 }
160
getProductStrategyForAttributes(const audio_attributes_t & attr) const161 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
162 const audio_attributes_t &attr) const
163 {
164 for (const auto &iter : *this) {
165 if (iter.second->matches(attr)) {
166 return iter.second->getId();
167 }
168 }
169 ALOGV("%s: No matching product strategy for attributes %s, return default", __FUNCTION__,
170 toString(attr).c_str());
171 return getDefault();
172 }
173
getAttributesForStreamType(audio_stream_type_t stream) const174 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
175 {
176 for (const auto &iter : *this) {
177 const auto strategy = iter.second;
178 if (strategy->supportStreamType(stream)) {
179 return strategy->getAttributesForStreamType(stream);
180 }
181 }
182 ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
183 toString(stream).c_str());
184 return {};
185 }
186
getStreamTypeForAttributes(const audio_attributes_t & attr) const187 audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
188 const audio_attributes_t &attr) const
189 {
190 for (const auto &iter : *this) {
191 audio_stream_type_t stream = iter.second->getStreamTypeForAttributes(attr);
192 if (stream != AUDIO_STREAM_DEFAULT) {
193 return stream;
194 }
195 }
196 ALOGV("%s: No product strategy for attributes %s, using default (aka MUSIC)", __FUNCTION__,
197 toString(attr).c_str());
198 return AUDIO_STREAM_MUSIC;
199 }
200
getDefault() const201 product_strategy_t ProductStrategyMap::getDefault() const
202 {
203 if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
204 return mDefaultStrategy;
205 }
206 for (const auto &iter : *this) {
207 if (iter.second->isDefault()) {
208 ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
209 return iter.second->getId();
210 }
211 }
212 ALOGE("%s: No default product strategy defined", __FUNCTION__);
213 return PRODUCT_STRATEGY_NONE;
214 }
215
getAttributesForProductStrategy(product_strategy_t strategy) const216 audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
217 product_strategy_t strategy) const
218 {
219 if (find(strategy) == end()) {
220 ALOGE("Invalid %d strategy requested", strategy);
221 return AUDIO_ATTRIBUTES_INITIALIZER;
222 }
223 return at(strategy)->getAudioAttributes()[0];
224 }
225
getProductStrategyForStream(audio_stream_type_t stream) const226 product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
227 {
228 for (const auto &iter : *this) {
229 if (iter.second->supportStreamType(stream)) {
230 return iter.second->getId();
231 }
232 }
233 ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
234 return getDefault();
235 }
236
237
getDeviceTypesForProductStrategy(product_strategy_t strategy) const238 audio_devices_t ProductStrategyMap::getDeviceTypesForProductStrategy(
239 product_strategy_t strategy) const
240 {
241 if (find(strategy) == end()) {
242 ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
243 product_strategy_t defaultStrategy = getDefault();
244 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
245 return AUDIO_DEVICE_NONE;
246 }
247 return at(getDefault())->getDeviceTypes();
248 }
249 return at(strategy)->getDeviceTypes();
250 }
251
getDeviceAddressForProductStrategy(product_strategy_t psId) const252 std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
253 {
254 if (find(psId) == end()) {
255 ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
256 product_strategy_t defaultStrategy = getDefault();
257 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
258 return {};
259 }
260 return at(getDefault())->getDeviceAddress();
261 }
262 return at(psId)->getDeviceAddress();
263 }
264
getVolumeGroupForAttributes(const audio_attributes_t & attr) const265 volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
266 {
267 for (const auto &iter : *this) {
268 volume_group_t group = iter.second->getVolumeGroupForAttributes(attr);
269 if (group != VOLUME_GROUP_NONE) {
270 return group;
271 }
272 }
273 return getDefaultVolumeGroup();
274 }
275
getVolumeGroupForStreamType(audio_stream_type_t stream) const276 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const
277 {
278 for (const auto &iter : *this) {
279 volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
280 if (group != VOLUME_GROUP_NONE) {
281 return group;
282 }
283 }
284 ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
285 return getDefaultVolumeGroup();
286 }
287
getDefaultVolumeGroup() const288 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
289 {
290 product_strategy_t defaultStrategy = getDefault();
291 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
292 return VOLUME_GROUP_NONE;
293 }
294 return at(defaultStrategy)->getDefaultVolumeGroup();
295 }
296
initialize()297 void ProductStrategyMap::initialize()
298 {
299 mDefaultStrategy = getDefault();
300 ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
301 }
302
dump(String8 * dst,int spaces) const303 void ProductStrategyMap::dump(String8 *dst, int spaces) const
304 {
305 dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
306 for (const auto &iter : *this) {
307 iter.second->dump(dst, spaces + 2);
308 }
309 }
310
311 }
312
313