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 32 ProductStrategy::ProductStrategy(const std::string &name) : 33 mName(name), 34 mId(static_cast<product_strategy_t>(HandleGenerator<uint32_t>::getNextHandle())) 35 { 36 } 37 38 void ProductStrategy::addAttributes(const AudioAttributes &audioAttributes) 39 { 40 mAttributesVector.push_back(audioAttributes); 41 } 42 43 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 52 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 64 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 72 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 81 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 89 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 95 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 107 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 114 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 124 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 134 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 141 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 161 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 174 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 187 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 201 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 216 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 226 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 238 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 252 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 265 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 276 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 288 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 297 void ProductStrategyMap::initialize() 298 { 299 mDefaultStrategy = getDefault(); 300 ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found"); 301 } 302 303 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