• 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 VolumeGroupAttributes & volumeGroupAttributes)39 void ProductStrategy::addAttributes(const VolumeGroupAttributes &volumeGroupAttributes)
40 {
41     mAttributesVector.push_back(volumeGroupAttributes);
42 }
43 
listVolumeGroupAttributes() const44 std::vector<android::VolumeGroupAttributes> ProductStrategy::listVolumeGroupAttributes() const
45 {
46     std::vector<android::VolumeGroupAttributes> androidAa;
47     for (const auto &attr : mAttributesVector) {
48         androidAa.push_back({attr.getGroupId(), attr.getStreamType(), attr.getAttributes()});
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.getAttributes());
58     }
59     if (not attrVector.empty()) {
60         return attrVector;
61     }
62     return { AUDIO_ATTRIBUTES_INITIALIZER };
63 }
64 
matchesScore(const audio_attributes_t attr) const65 int ProductStrategy::matchesScore(const audio_attributes_t attr) const
66 {
67     int strategyScore = AudioProductStrategy::NO_MATCH;
68     for (const auto &attrGroup : mAttributesVector) {
69         int score = AudioProductStrategy::attributesMatchesScore(attrGroup.getAttributes(), attr);
70         if (score == AudioProductStrategy::MATCH_EQUALS) {
71             return score;
72         }
73         strategyScore = std::max(score, strategyScore);
74     }
75     return strategyScore;
76 }
77 
getAttributesForStreamType(audio_stream_type_t streamType) const78 audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
79 {
80     const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
81                                    [&streamType](const auto &supportedAttr) {
82         return supportedAttr.getStreamType() == streamType; });
83     return iter != end(mAttributesVector) ? iter->getAttributes() : AUDIO_ATTRIBUTES_INITIALIZER;
84 }
85 
isDefault() const86 bool ProductStrategy::isDefault() const
87 {
88     return std::find_if(begin(mAttributesVector), end(mAttributesVector), [](const auto &attr) {
89         return attr.getAttributes() == defaultAttr; }) != end(mAttributesVector);
90 }
91 
getSupportedStreams() const92 StreamTypeVector ProductStrategy::getSupportedStreams() const
93 {
94     StreamTypeVector streams;
95     for (const auto &supportedAttr : mAttributesVector) {
96         if (std::find(begin(streams), end(streams), supportedAttr.getStreamType())
97                 == end(streams) && supportedAttr.getStreamType() != AUDIO_STREAM_DEFAULT) {
98             streams.push_back(supportedAttr.getStreamType());
99         }
100     }
101     return streams;
102 }
103 
supportStreamType(const audio_stream_type_t & streamType) const104 bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) const
105 {
106     return std::find_if(begin(mAttributesVector), end(mAttributesVector),
107                         [&streamType](const auto &supportedAttr) {
108         return supportedAttr.getStreamType() == streamType; }) != end(mAttributesVector);
109 }
110 
getVolumeGroupForStreamType(audio_stream_type_t stream) const111 volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const
112 {
113     for (const auto &supportedAttr : mAttributesVector) {
114         if (supportedAttr.getStreamType() == stream) {
115             return supportedAttr.getGroupId();
116         }
117     }
118     return VOLUME_GROUP_NONE;
119 }
120 
getDefaultVolumeGroup() const121 volume_group_t ProductStrategy::getDefaultVolumeGroup() const
122 {
123     const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
124                                     [](const auto &attr) {
125         return attr.getAttributes() == defaultAttr;
126     });
127     return iter != end(mAttributesVector) ? iter->getGroupId() : VOLUME_GROUP_NONE;
128 }
129 
dump(String8 * dst,int spaces) const130 void ProductStrategy::dump(String8 *dst, int spaces) const
131 {
132     dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
133     std::string deviceLiteral = deviceTypesToString(mApplicableDevices);
134     dst->appendFormat("%*sSelected Device: {%s, @:%s}\n", spaces + 2, "",
135                        deviceLiteral.c_str(), mDeviceAddress.c_str());
136 
137     for (const auto &attr : mAttributesVector) {
138         dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.getGroupId(),
139                           android::toString(attr.getStreamType()).c_str());
140         dst->appendFormat("%*s Attributes: ", spaces + 3, "");
141         std::string attStr = attr.getAttributes() == defaultAttr ?
142                 "{ Any }" : android::toString(attr.getAttributes());
143         dst->appendFormat("%s\n", attStr.c_str());
144     }
145 }
146 
getProductStrategyForAttributes(const audio_attributes_t & attributes,bool fallbackOnDefault) const147 product_strategy_t ProductStrategyMap::getProductStrategyForAttributes(
148         const audio_attributes_t &attributes, bool fallbackOnDefault) const
149 {
150     product_strategy_t bestStrategyOrdefault = PRODUCT_STRATEGY_NONE;
151     int matchScore = AudioProductStrategy::NO_MATCH;
152     for (const auto &iter : *this) {
153         int score = iter.second->matchesScore(attributes);
154         if (score == AudioProductStrategy::MATCH_EQUALS) {
155             return iter.second->getId();
156         }
157         if (score > matchScore) {
158             bestStrategyOrdefault = iter.second->getId();
159             matchScore = score;
160         }
161     }
162     return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
163             bestStrategyOrdefault : PRODUCT_STRATEGY_NONE;
164 }
165 
getAttributesForStreamType(audio_stream_type_t stream) const166 audio_attributes_t ProductStrategyMap::getAttributesForStreamType(audio_stream_type_t stream) const
167 {
168     for (const auto &iter : *this) {
169         const auto strategy = iter.second;
170         if (strategy->supportStreamType(stream)) {
171             return strategy->getAttributesForStreamType(stream);
172         }
173     }
174     ALOGV("%s: No product strategy for stream %s, using default", __FUNCTION__,
175           toString(stream).c_str());
176     return {};
177 }
178 
getDefault() const179 product_strategy_t ProductStrategyMap::getDefault() const
180 {
181     if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) {
182         return mDefaultStrategy;
183     }
184     for (const auto &iter : *this) {
185         if (iter.second->isDefault()) {
186             ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str());
187             return iter.second->getId();
188         }
189     }
190     ALOGE("%s: No default product strategy defined", __FUNCTION__);
191     return PRODUCT_STRATEGY_NONE;
192 }
193 
getAttributesForProductStrategy(product_strategy_t strategy) const194 audio_attributes_t ProductStrategyMap::getAttributesForProductStrategy(
195         product_strategy_t strategy) const
196 {
197     if (find(strategy) == end()) {
198         ALOGE("Invalid %d strategy requested", strategy);
199         return AUDIO_ATTRIBUTES_INITIALIZER;
200     }
201     return at(strategy)->getAudioAttributes()[0];
202 }
203 
getProductStrategyForStream(audio_stream_type_t stream) const204 product_strategy_t ProductStrategyMap::getProductStrategyForStream(audio_stream_type_t stream) const
205 {
206     for (const auto &iter : *this) {
207         if (iter.second->supportStreamType(stream)) {
208             return iter.second->getId();
209         }
210     }
211     ALOGV("%s: No product strategy for stream %d, using default", __FUNCTION__, stream);
212     return getDefault();
213 }
214 
215 
getDeviceTypesForProductStrategy(product_strategy_t strategy) const216 DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
217         product_strategy_t strategy) const
218 {
219     if (find(strategy) == end()) {
220         ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
221         product_strategy_t defaultStrategy = getDefault();
222         if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
223             return {AUDIO_DEVICE_NONE};
224         }
225         return at(getDefault())->getDeviceTypes();
226     }
227     return at(strategy)->getDeviceTypes();
228 }
229 
getDeviceAddressForProductStrategy(product_strategy_t psId) const230 std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strategy_t psId) const
231 {
232     if (find(psId) == end()) {
233         ALOGE("Invalid %d strategy requested, returning device for default strategy", psId);
234         product_strategy_t defaultStrategy = getDefault();
235         if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
236             return {};
237         }
238         return at(getDefault())->getDeviceAddress();
239     }
240     return at(psId)->getDeviceAddress();
241 }
242 
getVolumeGroupAttributesForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const243 VolumeGroupAttributes ProductStrategyMap::getVolumeGroupAttributesForAttributes(
244         const audio_attributes_t &attr, bool fallbackOnDefault) const
245 {
246     int matchScore = AudioProductStrategy::NO_MATCH;
247     VolumeGroupAttributes bestVolumeGroupAttributes = {};
248     for (const auto &iter : *this) {
249         for (const auto &volGroupAttr : iter.second->getVolumeGroupAttributes()) {
250             int score = volGroupAttr.matchesScore(attr);
251             if (score == AudioProductStrategy::MATCH_EQUALS) {
252                 return volGroupAttr;
253             }
254             if (score > matchScore) {
255                 matchScore = score;
256                 bestVolumeGroupAttributes = volGroupAttr;
257             }
258         }
259     }
260     return (matchScore != AudioProductStrategy::MATCH_ON_DEFAULT_SCORE || fallbackOnDefault) ?
261             bestVolumeGroupAttributes : VolumeGroupAttributes();
262 }
263 
getStreamTypeForAttributes(const audio_attributes_t & attr) const264 audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes(
265         const audio_attributes_t &attr) const
266 {
267     audio_stream_type_t streamType = getVolumeGroupAttributesForAttributes(
268             attr, /* fallbackOnDefault= */ true).getStreamType();
269     return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
270 }
271 
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const272 volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(
273         const audio_attributes_t &attr, bool fallbackOnDefault) const
274 {
275     return getVolumeGroupAttributesForAttributes(attr, fallbackOnDefault).getGroupId();
276 }
277 
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const278 volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(
279         audio_stream_type_t stream, bool fallbackOnDefault) const
280 {
281     for (const auto &iter : *this) {
282         volume_group_t group = iter.second->getVolumeGroupForStreamType(stream);
283         if (group != VOLUME_GROUP_NONE) {
284             return group;
285         }
286     }
287     ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
288     return fallbackOnDefault ? getDefaultVolumeGroup() : VOLUME_GROUP_NONE;
289 }
290 
getDefaultVolumeGroup() const291 volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
292 {
293     product_strategy_t defaultStrategy = getDefault();
294     if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
295         return VOLUME_GROUP_NONE;
296     }
297     return at(defaultStrategy)->getDefaultVolumeGroup();
298 }
299 
initialize()300 void ProductStrategyMap::initialize()
301 {
302     mDefaultStrategy = getDefault();
303     ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found");
304 }
305 
dump(String8 * dst,int spaces) const306 void ProductStrategyMap::dump(String8 *dst, int spaces) const
307 {
308     dst->appendFormat("%*sProduct Strategies dump:", spaces, "");
309     for (const auto &iter : *this) {
310         iter.second->dump(dst, spaces + 2);
311     }
312 }
313 
dumpProductStrategyDevicesRoleMap(const ProductStrategyDevicesRoleMap & productStrategyDeviceRoleMap,String8 * dst,int spaces)314 void dumpProductStrategyDevicesRoleMap(
315         const ProductStrategyDevicesRoleMap& productStrategyDeviceRoleMap,
316         String8 *dst,
317         int spaces) {
318     dst->appendFormat("\n%*sDevice role per product strategy dump:", spaces, "");
319     for (const auto& [strategyRolePair, devices] : productStrategyDeviceRoleMap) {
320         dst->appendFormat("\n%*sStrategy(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
321                 strategyRolePair.first, strategyRolePair.second,
322                 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
323     }
324     dst->appendFormat("\n");
325 }
326 }
327