• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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