Home | History | Annotate | Download | only in src
      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