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 || uint32_t(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 
setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,audio_policy_dev_state_t state)66 status_t EngineBase::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
67                                               audio_policy_dev_state_t state)
68 {
69     audio_devices_t deviceType = devDesc->type();
70     if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)) {
71         mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
72     }
73 
74     return NO_ERROR;
75 }
76 
getProductStrategyForAttributes(const audio_attributes_t & attr) const77 product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
78 {
79     return mProductStrategies.getProductStrategyForAttributes(attr);
80 }
81 
getStreamTypeForAttributes(const audio_attributes_t & attr) const82 audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
83 {
84     return mProductStrategies.getStreamTypeForAttributes(attr);
85 }
86 
getAttributesForStreamType(audio_stream_type_t stream) const87 audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const
88 {
89     return mProductStrategies.getAttributesForStreamType(stream);
90 }
91 
getProductStrategyForStream(audio_stream_type_t stream) const92 product_strategy_t EngineBase::getProductStrategyForStream(audio_stream_type_t stream) const
93 {
94     return mProductStrategies.getProductStrategyForStream(stream);
95 }
96 
getProductStrategyByName(const std::string & name) const97 product_strategy_t EngineBase::getProductStrategyByName(const std::string &name) const
98 {
99     for (const auto &iter : mProductStrategies) {
100         if (iter.second->getName() == name) {
101             return iter.second->getId();
102         }
103     }
104     return PRODUCT_STRATEGY_NONE;
105 }
106 
loadAudioPolicyEngineConfig()107 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
108 {
109     auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
110         // Ensure name unicity to prevent duplicate
111         const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
112                                      [&volumeConfig](const auto &volumeGroup) {
113                 return volumeConfig.name == volumeGroup.second->getName(); });
114         LOG_ALWAYS_FATAL_IF(iter != std::end(volumeGroups),
115                             "group name %s defined twice, review the configuration",
116                             volumeConfig.name.c_str());
117 
118         sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
119                                                       volumeConfig.indexMax);
120         volumeGroups[volumeGroup->getId()] = volumeGroup;
121 
122         for (auto &configCurve : volumeConfig.volumeCurves) {
123             device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
124             if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
125                 ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
126                 continue;
127             }
128             sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
129             for (auto &point : configCurve.curvePoints) {
130                 curve->add({point.index, point.attenuationInMb});
131             }
132             volumeGroup->add(curve);
133         }
134         return volumeGroup;
135     };
136     auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
137         for (const auto &attr : group.attributesVect) {
138             strategy->addAttributes({group.stream, volumeGroup->getId(), attr});
139             volumeGroup->addSupportedAttributes(attr);
140         }
141     };
142     auto checkStreamForGroups = [](auto streamType, const auto &volumeGroups) {
143         const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
144                                      [&streamType](const auto &volumeGroup) {
145             const auto& streams = volumeGroup.second->getStreamTypes();
146             return std::find(std::begin(streams), std::end(streams), streamType) !=
147                     std::end(streams);
148         });
149         return iter != end(volumeGroups);
150     };
151 
152     auto result = engineConfig::parse();
153     if (result.parsedConfig == nullptr) {
154         ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
155         engineConfig::Config config = gDefaultEngineConfig;
156         android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
157         result = {std::make_unique<engineConfig::Config>(config),
158                   static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
159     } else {
160         // Append for internal use only volume groups (e.g. rerouting/patch)
161         result.parsedConfig->volumeGroups.insert(
162                     std::end(result.parsedConfig->volumeGroups),
163                     std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
164     }
165     // Append for internal use only strategies (e.g. rerouting/patch)
166     result.parsedConfig->productStrategies.insert(
167                 std::end(result.parsedConfig->productStrategies),
168                 std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
169 
170 
171     ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
172 
173     engineConfig::VolumeGroup defaultVolumeConfig;
174     engineConfig::VolumeGroup defaultSystemVolumeConfig;
175     for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
176         // save default volume config for streams not defined in configuration
177         if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
178             defaultVolumeConfig = volumeConfig;
179         }
180         if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {
181             defaultSystemVolumeConfig = volumeConfig;
182         }
183         loadVolumeConfig(mVolumeGroups, volumeConfig);
184     }
185     for (auto& strategyConfig : result.parsedConfig->productStrategies) {
186         sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
187         for (const auto &group : strategyConfig.attributesGroups) {
188             const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
189                                          [&group](const auto &volumeGroup) {
190                     return group.volumeGroup == volumeGroup.second->getName(); });
191             sp<VolumeGroup> volumeGroup = nullptr;
192             // If no volume group provided for this strategy, creates a new one using
193             // Music Volume Group configuration (considered as the default)
194             if (iter == end(mVolumeGroups)) {
195                 engineConfig::VolumeGroup volumeConfig;
196                 if (group.stream >= AUDIO_STREAM_PUBLIC_CNT) {
197                     volumeConfig = defaultSystemVolumeConfig;
198                 } else {
199                     volumeConfig = defaultVolumeConfig;
200                 }
201                 ALOGW("%s: No configuration of %s found, using default volume configuration"
202                         , __FUNCTION__, group.volumeGroup.c_str());
203                 volumeConfig.name = group.volumeGroup;
204                 volumeGroup = loadVolumeConfig(mVolumeGroups, volumeConfig);
205             } else {
206                 volumeGroup = iter->second;
207             }
208             if (group.stream != AUDIO_STREAM_DEFAULT) {
209                 // A legacy stream can be assigned once to a volume group
210                 LOG_ALWAYS_FATAL_IF(checkStreamForGroups(group.stream, mVolumeGroups),
211                                     "stream %s already assigned to a volume group, "
212                                     "review the configuration", toString(group.stream).c_str());
213                 volumeGroup->addSupportedStream(group.stream);
214             }
215             addSupportedAttributesToGroup(group, volumeGroup, strategy);
216         }
217         product_strategy_t strategyId = strategy->getId();
218         mProductStrategies[strategyId] = strategy;
219     }
220     mProductStrategies.initialize();
221     return result;
222 }
223 
getOrderedProductStrategies() const224 StrategyVector EngineBase::getOrderedProductStrategies() const
225 {
226     auto findByFlag = [](const auto &productStrategies, auto flag) {
227         return std::find_if(begin(productStrategies), end(productStrategies),
228                             [&](const auto &strategy) {
229             for (const auto &attributes : strategy.second->getAudioAttributes()) {
230                 if ((attributes.flags & flag) == flag) {
231                     return true;
232                 }
233             }
234             return false;
235         });
236     };
237     auto strategies = mProductStrategies;
238     auto enforcedAudibleStrategyIter = findByFlag(strategies, AUDIO_FLAG_AUDIBILITY_ENFORCED);
239 
240     if (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED &&
241             enforcedAudibleStrategyIter != strategies.end()) {
242         auto enforcedAudibleStrategy = *enforcedAudibleStrategyIter;
243         strategies.erase(enforcedAudibleStrategyIter);
244         strategies.insert(begin(strategies), enforcedAudibleStrategy);
245     }
246     StrategyVector orderedStrategies;
247     for (const auto &iter : strategies) {
248         orderedStrategies.push_back(iter.second->getId());
249     }
250     return orderedStrategies;
251 }
252 
getStreamTypesForProductStrategy(product_strategy_t ps) const253 StreamTypeVector EngineBase::getStreamTypesForProductStrategy(product_strategy_t ps) const
254 {
255     // @TODO default music stream to control volume if no group?
256     return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
257                 mProductStrategies.at(ps)->getSupportedStreams() :
258                 StreamTypeVector(AUDIO_STREAM_MUSIC);
259 }
260 
getAllAttributesForProductStrategy(product_strategy_t ps) const261 AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const
262 {
263     return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
264                 mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector();
265 }
266 
listAudioProductStrategies(AudioProductStrategyVector & strategies) const267 status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &strategies) const
268 {
269     for (const auto &iter : mProductStrategies) {
270         const auto &productStrategy = iter.second;
271         strategies.push_back(
272         {productStrategy->getName(), productStrategy->listAudioAttributes(),
273          productStrategy->getId()});
274     }
275     return NO_ERROR;
276 }
277 
getVolumeCurvesForAttributes(const audio_attributes_t & attr) const278 VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const
279 {
280     volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr);
281     const auto &iter = mVolumeGroups.find(volGr);
282     LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str());
283     return mVolumeGroups.at(volGr)->getVolumeCurves();
284 }
285 
getVolumeCurvesForStreamType(audio_stream_type_t stream) const286 VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
287 {
288     volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
289     if (volGr == VOLUME_GROUP_NONE) {
290         volGr = mProductStrategies.getDefaultVolumeGroup();
291     }
292     const auto &iter = mVolumeGroups.find(volGr);
293     LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
294                 toString(stream).c_str());
295     return mVolumeGroups.at(volGr)->getVolumeCurves();
296 }
297 
switchVolumeCurve(audio_stream_type_t streamSrc,audio_stream_type_t streamDst)298 status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
299 {
300     auto srcCurves = getVolumeCurvesForStreamType(streamSrc);
301     auto dstCurves = getVolumeCurvesForStreamType(streamDst);
302 
303     if (srcCurves == nullptr || dstCurves == nullptr) {
304         return BAD_VALUE;
305     }
306     return dstCurves->switchCurvesFrom(*srcCurves);
307 }
308 
restoreOriginVolumeCurve(audio_stream_type_t stream)309 status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream)
310 {
311     VolumeCurves *curves = getVolumeCurvesForStreamType(stream);
312     return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE;
313 }
314 
getVolumeGroups() const315 VolumeGroupVector EngineBase::getVolumeGroups() const
316 {
317     VolumeGroupVector group;
318     for (const auto &iter : mVolumeGroups) {
319         group.push_back(iter.first);
320     }
321     return group;
322 }
323 
getVolumeGroupForAttributes(const audio_attributes_t & attr) const324 volume_group_t EngineBase::getVolumeGroupForAttributes(const audio_attributes_t &attr) const
325 {
326     return mProductStrategies.getVolumeGroupForAttributes(attr);
327 }
328 
getVolumeGroupForStreamType(audio_stream_type_t stream) const329 volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t stream) const
330 {
331     return mProductStrategies.getVolumeGroupForStreamType(stream);
332 }
333 
listAudioVolumeGroups(AudioVolumeGroupVector & groups) const334 status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
335 {
336     for (const auto &iter : mVolumeGroups) {
337         groups.push_back({iter.second->getName(), iter.second->getId(),
338                           iter.second->getSupportedAttributes(), iter.second->getStreamTypes()});
339     }
340     return NO_ERROR;
341 }
342 
setPreferredDeviceForStrategy(product_strategy_t strategy,const AudioDeviceTypeAddr & device)343 status_t EngineBase::setPreferredDeviceForStrategy(product_strategy_t strategy,
344             const AudioDeviceTypeAddr &device)
345 {
346     // verify strategy exists
347     if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
348         ALOGE("%s invalid strategy %u", __func__, strategy);
349         return BAD_VALUE;
350     }
351 
352     mProductStrategyPreferredDevices[strategy] = device;
353     return NO_ERROR;
354 }
355 
removePreferredDeviceForStrategy(product_strategy_t strategy)356 status_t EngineBase::removePreferredDeviceForStrategy(product_strategy_t strategy)
357 {
358     // verify strategy exists
359     if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
360         ALOGE("%s invalid strategy %u", __func__, strategy);
361         return BAD_VALUE;
362     }
363 
364     if (mProductStrategyPreferredDevices.erase(strategy) == 0) {
365         // no preferred device was set
366         return NAME_NOT_FOUND;
367     }
368     return NO_ERROR;
369 }
370 
getPreferredDeviceForStrategy(product_strategy_t strategy,AudioDeviceTypeAddr & device) const371 status_t EngineBase::getPreferredDeviceForStrategy(product_strategy_t strategy,
372             AudioDeviceTypeAddr &device) const
373 {
374     // verify strategy exists
375     if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
376         ALOGE("%s unknown strategy %u", __func__, strategy);
377         return BAD_VALUE;
378     }
379     // preferred device for this strategy?
380     auto devIt = mProductStrategyPreferredDevices.find(strategy);
381     if (devIt == mProductStrategyPreferredDevices.end()) {
382         ALOGV("%s no preferred device for strategy %u", __func__, strategy);
383         return NAME_NOT_FOUND;
384     }
385 
386     device = devIt->second;
387     return NO_ERROR;
388 }
389 
dump(String8 * dst) const390 void EngineBase::dump(String8 *dst) const
391 {
392     mProductStrategies.dump(dst, 2);
393     mProductStrategyPreferredDevices.dump(dst, 2);
394     mVolumeGroups.dump(dst, 2);
395 }
396 
397 } // namespace audio_policy
398 } // namespace android
399