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