• 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/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 
setObserver(AudioPolicyManagerObserver * observer)27 void EngineBase::setObserver(AudioPolicyManagerObserver *observer)
28 {
29     ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
30     mApmObserver = observer;
31 }
32 
initCheck()33 status_t EngineBase::initCheck()
34 {
35     return (mApmObserver != nullptr)? NO_ERROR : NO_INIT;
36 }
37 
setPhoneState(audio_mode_t state)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 
getProductStrategyForAttributes(const audio_attributes_t & attr) const66 product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
67 {
68     return mProductStrategies.getProductStrategyForAttributes(attr);
69 }
70 
getStreamTypeForAttributes(const audio_attributes_t & attr) const71 audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
72 {
73     return mProductStrategies.getStreamTypeForAttributes(attr);
74 }
75 
getAttributesForStreamType(audio_stream_type_t stream) const76 audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const
77 {
78     return mProductStrategies.getAttributesForStreamType(stream);
79 }
80 
getProductStrategyForStream(audio_stream_type_t stream) const81 product_strategy_t EngineBase::getProductStrategyForStream(audio_stream_type_t stream) const
82 {
83     return mProductStrategies.getProductStrategyForStream(stream);
84 }
85 
getProductStrategyByName(const std::string & name) const86 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 
loadAudioPolicyEngineConfig()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 
getOrderedProductStrategies() const156 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 
getStreamTypesForProductStrategy(product_strategy_t ps) const185 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 
getAllAttributesForProductStrategy(product_strategy_t ps) const193 AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const
194 {
195     return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
196                 mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector();
197 }
198 
listAudioProductStrategies(AudioProductStrategyVector & strategies) const199 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 
getVolumeCurvesForAttributes(const audio_attributes_t & attr) const210 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 
getVolumeCurvesForStreamType(audio_stream_type_t stream) const218 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 
switchVolumeCurve(audio_stream_type_t streamSrc,audio_stream_type_t streamDst)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 
restoreOriginVolumeCurve(audio_stream_type_t stream)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 
getVolumeGroups() const247 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 
getVolumeGroupForAttributes(const audio_attributes_t & attr) const256 volume_group_t EngineBase::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
257 {
258     return mProductStrategies.getVolumeGroupForAttributes(attr);
259 }
260 
getVolumeGroupForStreamType(audio_stream_type_t stream) const261 volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t stream) const
262 {
263     return mProductStrategies.getVolumeGroupForStreamType(stream);
264 }
265 
listAudioVolumeGroups(AudioVolumeGroupVector & groups) const266 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 
dump(String8 * dst) const275 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