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 = deviceTypesToString(mApplicableDevices);
154 dst->appendFormat("%*sSelected Device: {%s, @:%s}\n", spaces + 2, "",
155 deviceLiteral.c_str(), mDeviceAddress.c_str());
156
157 for (const auto &attr : mAttributesVector) {
158 dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mVolumeGroup,
159 android::toString(attr.mStream).c_str());
160 dst->appendFormat("%*s Attributes: ", spaces + 3, "");
161 std::string attStr =
162 attr.mAttributes == defaultAttr ? "{ Any }" : android::toString(attr.mAttributes);
163 dst->appendFormat("%s\n", attStr.c_str());
164 }
165 }
166
getProductStrategyForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const167 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
168 const audio_attributes_t &attr, bool fallbackOnDefault) const
169 {
170 for (const auto &iter : *this) {
171 if (iter.second->matches(attr)) {
172 return iter.second->getId();
173 }
174 }
175 ALOGV("%s: No matching product strategy for attributes %s, return default", __FUNCTION__,
176 toString(attr).c_str());
177 return fallbackOnDefault? getDefault() : PRODUCT_STRATEGY_NONE;
178 }
179
getAttributesForStreamType(audio_stream_type_t stream) const180 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
181 {
182 for (const auto &iter : *this) {
183 const auto strategy = iter.second;
184 if (strategy->supportStreamType(stream)) {
185 return strategy->getAttributesForStreamType(stream);
186 }
187 }
188 ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
189 toString(stream).c_str());
190 return {};
191 }
192
getStreamTypeForAttributes(const audio_attributes_t & attr) const193 audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
194 const audio_attributes_t &attr) const
195 {
196 for (const auto &iter : *this) {
197 audio_stream_type_t stream = iter.second->getStreamTypeForAttributes(attr);
198 if (stream != AUDIO_STREAM_DEFAULT) {
199 return stream;
200 }
201 }
202 ALOGV("%s: No product strategy for attributes %s, using default (aka MUSIC)", __FUNCTION__,
203 toString(attr).c_str());
204 return AUDIO_STREAM_MUSIC;
205 }
206
getDefault() const207 product_strategy_t ProductStrategyMap::getDefault() const
208 {
209 if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
210 return mDefaultStrategy;
211 }
212 for (const auto &iter : *this) {
213 if (iter.second->isDefault()) {
214 ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
215 return iter.second->getId();
216 }
217 }
218 ALOGE("%s: No default product strategy defined", __FUNCTION__);
219 return PRODUCT_STRATEGY_NONE;
220 }
221
getAttributesForProductStrategy(product_strategy_t strategy) const222 audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
223 product_strategy_t strategy) const
224 {
225 if (find(strategy) == end()) {
226 ALOGE("Invalid %d strategy requested", strategy);
227 return AUDIO_ATTRIBUTES_INITIALIZER;
228 }
229 return at(strategy)->getAudioAttributes()[0];
230 }
231
getProductStrategyForStream(audio_stream_type_t stream) const232 product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
233 {
234 for (const auto &iter : *this) {
235 if (iter.second->supportStreamType(stream)) {
236 return iter.second->getId();
237 }
238 }
239 ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
240 return getDefault();
241 }
242
243
getDeviceTypesForProductStrategy(product_strategy_t strategy) const244 DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
245 product_strategy_t strategy) const
246 {
247 if (find(strategy) == end()) {
248 ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
249 product_strategy_t defaultStrategy = getDefault();
250 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
251 return {AUDIO_DEVICE_NONE};
252 }
253 return at(getDefault())->getDeviceTypes();
254 }
255 return at(strategy)->getDeviceTypes();
256 }
257
getDeviceAddressForProductStrategy(product_strategy_t psId) const258 std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
259 {
260 if (find(psId) == end()) {
261 ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
262 product_strategy_t defaultStrategy = getDefault();
263 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
264 return {};
265 }
266 return at(getDefault())->getDeviceAddress();
267 }
268 return at(psId)->getDeviceAddress();
269 }
270
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const271 volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(
272 const audio_attributes_t &attr, bool fallbackOnDefault) const
273 {
274 for (const auto &iter : *this) {
275 volume_group_t group = iter.second->getVolumeGroupForAttributes(attr);
276 if (group != VOLUME_GROUP_NONE) {
277 return group;
278 }
279 }
280 return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
281 }
282
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const283 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(
284 audio_stream_type_t stream, bool fallbackOnDefault) const
285 {
286 for (const auto &iter : *this) {
287 volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
288 if (group != VOLUME_GROUP_NONE) {
289 return group;
290 }
291 }
292 ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
293 return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
294 }
295
getDefaultVolumeGroup() const296 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
297 {
298 product_strategy_t defaultStrategy = getDefault();
299 if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
300 return VOLUME_GROUP_NONE;
301 }
302 return at(defaultStrategy)->getDefaultVolumeGroup();
303 }
304
initialize()305 void ProductStrategyMap::initialize()
306 {
307 mDefaultStrategy = getDefault();
308 ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
309 }
310
dump(String8 * dst,int spaces) const311 void ProductStrategyMap::dump(String8 *dst, int spaces) const
312 {
313 dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
314 for (const auto &iter : *this) {
315 iter.second->dump(dst, spaces + 2);
316 }
317 }
318
dumpProductStrategyDevicesRoleMap(const ProductStrategyDevicesRoleMap & productStrategyDeviceRoleMap,String8 * dst,int spaces)319 void dumpProductStrategyDevicesRoleMap(
320 const ProductStrategyDevicesRoleMap& productStrategyDeviceRoleMap,
321 String8 *dst,
322 int spaces) {
323 dst->appendFormat("\n%*sDevice role per product strategy dump:", spaces, "");
324 for (const auto& [strategyRolePair, devices] : productStrategyDeviceRoleMap) {
325 dst->appendFormat("\n%*sStrategy(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
326 strategyRolePair.first, strategyRolePair.second,
327 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
328 }
329 dst->appendFormat("\n");
330 }
331 }
332