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/Base" 18 //#define LOG_NDEBUG 0 19 20 #include "EngineBase.h" 21 #include "EngineDefaultConfig.h" 22 #include <TypeConverter.h> 23 24 namespace android { 25 namespace audio_policy { 26 27 void EngineBase::setObserver(AudioPolicyManagerObserver *observer) 28 { 29 ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer"); 30 mApmObserver = observer; 31 } 32 33 status_t EngineBase::initCheck() 34 { 35 return (mApmObserver != nullptr)? NO_ERROR : NO_INIT; 36 } 37 38 status_t EngineBase::setPhoneState(audio_mode_t state) 39 { 40 ALOGV("setPhoneState() state %d", state); 41 42 if (state < 0 || state >= AUDIO_MODE_CNT) { 43 ALOGW("setPhoneState() invalid state %d", state); 44 return BAD_VALUE; 45 } 46 47 if (state == mPhoneState ) { 48 ALOGW("setPhoneState() setting same state %d", state); 49 return BAD_VALUE; 50 } 51 52 // store previous phone state for management of sonification strategy below 53 int oldState = mPhoneState; 54 mPhoneState = state; 55 56 if (!is_state_in_call(oldState) && is_state_in_call(state)) { 57 ALOGV(" Entering call in setPhoneState()"); 58 switchVolumeCurve(AUDIO_STREAM_VOICE_CALL, AUDIO_STREAM_DTMF); 59 } else if (is_state_in_call(oldState) && !is_state_in_call(state)) { 60 ALOGV(" Exiting call in setPhoneState()"); 61 restoreOriginVolumeCurve(AUDIO_STREAM_DTMF); 62 } 63 return NO_ERROR; 64 } 65 66 product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const 67 { 68 return mProductStrategies.getProductStrategyForAttributes(attr); 69 } 70 71 audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const 72 { 73 return mProductStrategies.getStreamTypeForAttributes(attr); 74 } 75 76 audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const 77 { 78 return mProductStrategies.getAttributesForStreamType(stream); 79 } 80 81 product_strategy_t EngineBase::getProductStrategyForStream(audio_stream_type_t stream) const 82 { 83 return mProductStrategies.getProductStrategyForStream(stream); 84 } 85 86 product_strategy_t EngineBase::getProductStrategyByName(const std::string &name) const 87 { 88 for (const auto &iter : mProductStrategies) { 89 if (iter.second->getName() == name) { 90 return iter.second->getId(); 91 } 92 } 93 return PRODUCT_STRATEGY_NONE; 94 } 95 96 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig() 97 { 98 auto loadProductStrategies = 99 [](auto& strategyConfigs, auto& productStrategies, auto& volumeGroups) { 100 for (auto& strategyConfig : strategyConfigs) { 101 sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name); 102 for (const auto &group : strategyConfig.attributesGroups) { 103 const auto &iter = std::find_if(begin(volumeGroups), end(volumeGroups), 104 [&group](const auto &volumeGroup) { 105 return group.volumeGroup == volumeGroup.second->getName(); }); 106 ALOG_ASSERT(iter != end(volumeGroups), "Invalid Volume Group Name %s", 107 group.volumeGroup.c_str()); 108 if (group.stream != AUDIO_STREAM_DEFAULT) { 109 iter->second->addSupportedStream(group.stream); 110 } 111 for (const auto &attr : group.attributesVect) { 112 strategy->addAttributes({group.stream, iter->second->getId(), attr}); 113 iter->second->addSupportedAttributes(attr); 114 } 115 } 116 product_strategy_t strategyId = strategy->getId(); 117 productStrategies[strategyId] = strategy; 118 } 119 }; 120 auto loadVolumeGroups = [](auto &volumeConfigs, auto &volumeGroups) { 121 for (auto &volumeConfig : volumeConfigs) { 122 sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin, 123 volumeConfig.indexMax); 124 volumeGroups[volumeGroup->getId()] = volumeGroup; 125 126 for (auto &configCurve : volumeConfig.volumeCurves) { 127 device_category deviceCat = DEVICE_CATEGORY_SPEAKER; 128 if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) { 129 ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str()); 130 continue; 131 } 132 sp<VolumeCurve> curve = new VolumeCurve(deviceCat); 133 for (auto &point : configCurve.curvePoints) { 134 curve->add({point.index, point.attenuationInMb}); 135 } 136 volumeGroup->add(curve); 137 } 138 } 139 }; 140 auto result = engineConfig::parse(); 141 if (result.parsedConfig == nullptr) { 142 ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__); 143 engineConfig::Config config = gDefaultEngineConfig; 144 android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups); 145 result = {std::make_unique<engineConfig::Config>(config), 146 static_cast<size_t>(ret == NO_ERROR ? 0 : 1)}; 147 } 148 ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement); 149 loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups); 150 loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies, 151 mVolumeGroups); 152 mProductStrategies.initialize(); 153 return result; 154 } 155 156 StrategyVector EngineBase::getOrderedProductStrategies() const 157 { 158 auto findByFlag = [](const auto &productStrategies, auto flag) { 159 return std::find_if(begin(productStrategies), end(productStrategies), 160 [&](const auto &strategy) { 161 for (const auto &attributes : strategy.second->getAudioAttributes()) { 162 if ((attributes.flags & flag) == flag) { 163 return true; 164 } 165 } 166 return false; 167 }); 168 }; 169 auto strategies = mProductStrategies; 170 auto enforcedAudibleStrategyIter = findByFlag(strategies, AUDIO_FLAG_AUDIBILITY_ENFORCED); 171 172 if (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED && 173 enforcedAudibleStrategyIter != strategies.end()) { 174 auto enforcedAudibleStrategy = *enforcedAudibleStrategyIter; 175 strategies.erase(enforcedAudibleStrategyIter); 176 strategies.insert(begin(strategies), enforcedAudibleStrategy); 177 } 178 StrategyVector orderedStrategies; 179 for (const auto &iter : strategies) { 180 orderedStrategies.push_back(iter.second->getId()); 181 } 182 return orderedStrategies; 183 } 184 185 StreamTypeVector EngineBase::getStreamTypesForProductStrategy(product_strategy_t ps) const 186 { 187 // @TODO default music stream to control volume if no group? 188 return (mProductStrategies.find(ps) != end(mProductStrategies)) ? 189 mProductStrategies.at(ps)->getSupportedStreams() : 190 StreamTypeVector(AUDIO_STREAM_MUSIC); 191 } 192 193 AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const 194 { 195 return (mProductStrategies.find(ps) != end(mProductStrategies)) ? 196 mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector(); 197 } 198 199 status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &strategies) const 200 { 201 for (const auto &iter : mProductStrategies) { 202 const auto &productStrategy = iter.second; 203 strategies.push_back( 204 {productStrategy->getName(), productStrategy->listAudioAttributes(), 205 productStrategy->getId()}); 206 } 207 return NO_ERROR; 208 } 209 210 VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const 211 { 212 volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr); 213 const auto &iter = mVolumeGroups.find(volGr); 214 LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str()); 215 return mVolumeGroups.at(volGr)->getVolumeCurves(); 216 } 217 218 VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const 219 { 220 volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream); 221 if (volGr == VOLUME_GROUP_NONE) { 222 volGr = mProductStrategies.getDefaultVolumeGroup(); 223 } 224 const auto &iter = mVolumeGroups.find(volGr); 225 LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", 226 toString(stream).c_str()); 227 return mVolumeGroups.at(volGr)->getVolumeCurves(); 228 } 229 230 status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) 231 { 232 auto srcCurves = getVolumeCurvesForStreamType(streamSrc); 233 auto dstCurves = getVolumeCurvesForStreamType(streamDst); 234 235 if (srcCurves == nullptr || dstCurves == nullptr) { 236 return BAD_VALUE; 237 } 238 return dstCurves->switchCurvesFrom(*srcCurves); 239 } 240 241 status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream) 242 { 243 VolumeCurves *curves = getVolumeCurvesForStreamType(stream); 244 return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE; 245 } 246 247 VolumeGroupVector EngineBase::getVolumeGroups() const 248 { 249 VolumeGroupVector group; 250 for (const auto &iter : mVolumeGroups) { 251 group.push_back(iter.first); 252 } 253 return group; 254 } 255 256 volume_group_t EngineBase::getVolumeGroupForAttributes(const audio_attributes_t &attr) const 257 { 258 return mProductStrategies.getVolumeGroupForAttributes(attr); 259 } 260 261 volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t stream) const 262 { 263 return mProductStrategies.getVolumeGroupForStreamType(stream); 264 } 265 266 status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const 267 { 268 for (const auto &iter : mVolumeGroups) { 269 groups.push_back({iter.second->getName(), iter.second->getId(), 270 iter.second->getSupportedAttributes(), iter.second->getStreamTypes()}); 271 } 272 return NO_ERROR; 273 } 274 275 void EngineBase::dump(String8 *dst) const 276 { 277 mProductStrategies.dump(dst, 2); 278 mVolumeGroups.dump(dst, 2); 279 } 280 281 } // namespace audio_policy 282 } // namespace android 283