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