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