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 <functional>
21 #include <string>
22 #include <sys/stat.h>
23
24 #include "EngineBase.h"
25 #include "EngineDefaultConfig.h"
26 #include <TypeConverter.h>
27
28 namespace android {
29 namespace audio_policy {
30
setObserver(AudioPolicyManagerObserver * observer)31 void EngineBase::setObserver(AudioPolicyManagerObserver *observer)
32 {
33 ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
34 mApmObserver = observer;
35 }
36
initCheck()37 status_t EngineBase::initCheck()
38 {
39 return (mApmObserver != nullptr)? NO_ERROR : NO_INIT;
40 }
41
setPhoneState(audio_mode_t state)42 status_t EngineBase::setPhoneState(audio_mode_t state)
43 {
44 ALOGV("setPhoneState() state %d", state);
45
46 if (state < 0 || uint32_t(state) >= AUDIO_MODE_CNT) {
47 ALOGW("setPhoneState() invalid state %d", state);
48 return BAD_VALUE;
49 }
50
51 if (state == mPhoneState ) {
52 ALOGW("setPhoneState() setting same state %d", state);
53 return BAD_VALUE;
54 }
55
56 // store previous phone state for management of sonification strategy below
57 int oldState = mPhoneState;
58 mPhoneState = state;
59
60 if (!is_state_in_call(oldState) && is_state_in_call(state)) {
61 ALOGV(" Entering call in setPhoneState()");
62 switchVolumeCurve(AUDIO_STREAM_VOICE_CALL, AUDIO_STREAM_DTMF);
63 } else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
64 ALOGV(" Exiting call in setPhoneState()");
65 restoreOriginVolumeCurve(AUDIO_STREAM_DTMF);
66 }
67 return NO_ERROR;
68 }
69
setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,audio_policy_dev_state_t state)70 status_t EngineBase::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
71 audio_policy_dev_state_t state)
72 {
73 audio_devices_t deviceType = devDesc->type();
74 if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)
75 && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET
76 && deviceType != AUDIO_DEVICE_OUT_BLE_BROADCAST) {
77 // USB dock does not follow the rule of last removable device connected wins.
78 // It is only used if no removable device is connected or if set as preferred device
79 // LE audio broadcast device has a specific policy depending on active strategies and
80 // devices and does not follow the rule of last connected removable device.
81 mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
82 }
83
84 return NO_ERROR;
85 }
86
getProductStrategyForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const87 product_strategy_t EngineBase::getProductStrategyForAttributes(
88 const audio_attributes_t &attr, bool fallbackOnDefault) const
89 {
90 return mProductStrategies.getProductStrategyForAttributes(attr, fallbackOnDefault);
91 }
92
getStreamTypeForAttributes(const audio_attributes_t & attr) const93 audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
94 {
95 return mProductStrategies.getStreamTypeForAttributes(attr);
96 }
97
getAttributesForStreamType(audio_stream_type_t stream) const98 audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const
99 {
100 return mProductStrategies.getAttributesForStreamType(stream);
101 }
102
getProductStrategyForStream(audio_stream_type_t stream) const103 product_strategy_t EngineBase::getProductStrategyForStream(audio_stream_type_t stream) const
104 {
105 return mProductStrategies.getProductStrategyForStream(stream);
106 }
107
getProductStrategyByName(const std::string & name) const108 product_strategy_t EngineBase::getProductStrategyByName(const std::string &name) const
109 {
110 for (const auto &iter : mProductStrategies) {
111 if (iter.second->getName() == name) {
112 return iter.second->getId();
113 }
114 }
115 return PRODUCT_STRATEGY_NONE;
116 }
117
loadAudioPolicyEngineConfig(const media::audio::common::AudioHalEngineConfig & aidlConfig)118 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(
119 const media::audio::common::AudioHalEngineConfig& aidlConfig)
120 {
121 engineConfig::ParsingResult result = engineConfig::convert(aidlConfig);
122 if (result.parsedConfig == nullptr) {
123 ALOGE("%s: There was an error parsing AIDL data", __func__);
124 result = {std::make_unique<engineConfig::Config>(gDefaultEngineConfig), 1};
125 } else {
126 // It is allowed for the HAL to return an empty list of strategies.
127 if (result.parsedConfig->productStrategies.empty()) {
128 result.parsedConfig->productStrategies = gDefaultEngineConfig.productStrategies;
129 }
130 }
131 return processParsingResult(std::move(result));
132 }
133
loadAudioPolicyEngineConfig(const std::string & xmlFilePath)134 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
135 {
136 auto fileExists = [](const char* path) {
137 struct stat fileStat;
138 return stat(path, &fileStat) == 0 && S_ISREG(fileStat.st_mode);
139 };
140 const std::string filePath = xmlFilePath.empty() ? engineConfig::DEFAULT_PATH : xmlFilePath;
141 engineConfig::ParsingResult result =
142 fileExists(filePath.c_str()) ?
143 engineConfig::parse(filePath.c_str()) : engineConfig::ParsingResult{};
144 if (result.parsedConfig == nullptr) {
145 ALOGD("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
146 engineConfig::Config config = gDefaultEngineConfig;
147 android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
148 result = {std::make_unique<engineConfig::Config>(config),
149 static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
150 } else {
151 // Append for internal use only volume groups (e.g. rerouting/patch)
152 result.parsedConfig->volumeGroups.insert(
153 std::end(result.parsedConfig->volumeGroups),
154 std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
155 }
156 ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
157 return processParsingResult(std::move(result));
158 }
159
processParsingResult(engineConfig::ParsingResult && rawResult)160 engineConfig::ParsingResult EngineBase::processParsingResult(
161 engineConfig::ParsingResult&& rawResult)
162 {
163 auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
164 // Ensure volume group name uniqueness.
165 LOG_ALWAYS_FATAL_IF(std::any_of(std::begin(volumeGroups), std::end(volumeGroups),
166 [&volumeConfig](const auto &volumeGroup) {
167 return volumeConfig.name == volumeGroup.second->getName(); }),
168 "group name %s defined twice, review the configuration",
169 volumeConfig.name.c_str());
170
171 sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
172 volumeConfig.indexMax);
173 volumeGroups[volumeGroup->getId()] = volumeGroup;
174
175 for (auto &configCurve : volumeConfig.volumeCurves) {
176 device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
177 if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
178 ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
179 continue;
180 }
181 sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
182 for (auto &point : configCurve.curvePoints) {
183 curve->add({point.index, point.attenuationInMb});
184 }
185 volumeGroup->add(curve);
186 }
187 return volumeGroup;
188 };
189 auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
190 for (const auto &attr : group.attributesVect) {
191 strategy->addAttributes({volumeGroup->getId(), group.stream, attr});
192 volumeGroup->addSupportedAttributes(attr);
193 }
194 };
195 auto checkStreamForGroups = [](auto streamType, const auto &volumeGroups) {
196 const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
197 [&streamType](const auto &volumeGroup) {
198 const auto& streams = volumeGroup.second->getStreamTypes();
199 return std::find(std::begin(streams), std::end(streams), streamType) !=
200 std::end(streams);
201 });
202 return iter != end(volumeGroups);
203 };
204
205 auto result = std::move(rawResult);
206 // Append for internal use only strategies (e.g. rerouting/patch)
207 result.parsedConfig->productStrategies.insert(
208 std::end(result.parsedConfig->productStrategies),
209 std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
210
211 engineConfig::VolumeGroup defaultVolumeConfig;
212 engineConfig::VolumeGroup defaultSystemVolumeConfig;
213 for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
214 // save default volume config for streams not defined in configuration
215 if (volumeConfig.name.compare(audio_stream_type_to_string(AUDIO_STREAM_MUSIC)) == 0) {
216 defaultVolumeConfig = volumeConfig;
217 }
218 if (volumeConfig.name.compare(audio_stream_type_to_string(AUDIO_STREAM_PATCH)) == 0) {
219 defaultSystemVolumeConfig = volumeConfig;
220 }
221 loadVolumeConfig(mVolumeGroups, volumeConfig);
222 }
223 for (auto& strategyConfig : result.parsedConfig->productStrategies) {
224 sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
225 for (const auto &group : strategyConfig.attributesGroups) {
226 const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
227 [&group](const auto &volumeGroup) {
228 return group.volumeGroup == volumeGroup.second->getName(); });
229 sp<VolumeGroup> volumeGroup = nullptr;
230 // If no volume group provided for this strategy, creates a new one using
231 // Music Volume Group configuration (considered as the default)
232 if (iter == end(mVolumeGroups)) {
233 engineConfig::VolumeGroup volumeConfig;
234 if (group.stream >= AUDIO_STREAM_PUBLIC_CNT) {
235 volumeConfig = defaultSystemVolumeConfig;
236 } else {
237 volumeConfig = defaultVolumeConfig;
238 }
239 ALOGW("%s: No configuration of %s found, using default volume configuration"
240 , __FUNCTION__, group.volumeGroup.c_str());
241 volumeConfig.name = group.volumeGroup;
242 volumeGroup = loadVolumeConfig(mVolumeGroups, volumeConfig);
243 } else {
244 volumeGroup = iter->second;
245 }
246 if (group.stream != AUDIO_STREAM_DEFAULT) {
247 // A legacy stream can be assigned once to a volume group
248 LOG_ALWAYS_FATAL_IF(checkStreamForGroups(group.stream, mVolumeGroups),
249 "stream %s already assigned to a volume group, "
250 "review the configuration", toString(group.stream).c_str());
251 volumeGroup->addSupportedStream(group.stream);
252 }
253 addSupportedAttributesToGroup(group, volumeGroup, strategy);
254 }
255 product_strategy_t strategyId = strategy->getId();
256 mProductStrategies[strategyId] = strategy;
257 }
258 mProductStrategies.initialize();
259 return result;
260 }
261
getOrderedProductStrategies() const262 StrategyVector EngineBase::getOrderedProductStrategies() const
263 {
264 auto findByFlag = [](const auto &productStrategies, auto flag) {
265 return std::find_if(begin(productStrategies), end(productStrategies),
266 [&](const auto &strategy) {
267 for (const auto &attributes : strategy.second->getAudioAttributes()) {
268 if ((attributes.flags & flag) == flag) {
269 return true;
270 }
271 }
272 return false;
273 });
274 };
275 auto strategies = mProductStrategies;
276 auto enforcedAudibleStrategyIter = findByFlag(strategies, AUDIO_FLAG_AUDIBILITY_ENFORCED);
277
278 if (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED &&
279 enforcedAudibleStrategyIter != strategies.end()) {
280 auto enforcedAudibleStrategy = *enforcedAudibleStrategyIter;
281 strategies.erase(enforcedAudibleStrategyIter);
282 strategies.insert(begin(strategies), enforcedAudibleStrategy);
283 }
284 StrategyVector orderedStrategies;
285 for (const auto &iter : strategies) {
286 orderedStrategies.push_back(iter.second->getId());
287 }
288 return orderedStrategies;
289 }
290
getStreamTypesForProductStrategy(product_strategy_t ps) const291 StreamTypeVector EngineBase::getStreamTypesForProductStrategy(product_strategy_t ps) const
292 {
293 // @TODO default music stream to control volume if no group?
294 return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
295 mProductStrategies.at(ps)->getSupportedStreams() :
296 StreamTypeVector(AUDIO_STREAM_MUSIC);
297 }
298
getAllAttributesForProductStrategy(product_strategy_t ps) const299 AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const
300 {
301 return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
302 mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector();
303 }
304
listAudioProductStrategies(AudioProductStrategyVector & strategies) const305 status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &strategies) const
306 {
307 for (const auto &iter : mProductStrategies) {
308 const auto &productStrategy = iter.second;
309 strategies.push_back(
310 {productStrategy->getName(), productStrategy->listVolumeGroupAttributes(),
311 productStrategy->getId()});
312 }
313 return NO_ERROR;
314 }
315
getVolumeCurvesForAttributes(const audio_attributes_t & attr) const316 VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const
317 {
318 volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr);
319 const auto &iter = mVolumeGroups.find(volGr);
320 LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str());
321 return mVolumeGroups.at(volGr)->getVolumeCurves();
322 }
323
getVolumeCurvesForStreamType(audio_stream_type_t stream) const324 VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
325 {
326 volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
327 if (volGr == VOLUME_GROUP_NONE) {
328 volGr = mProductStrategies.getDefaultVolumeGroup();
329 }
330 const auto &iter = mVolumeGroups.find(volGr);
331 LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
332 toString(stream).c_str());
333 return mVolumeGroups.at(volGr)->getVolumeCurves();
334 }
335
switchVolumeCurve(audio_stream_type_t streamSrc,audio_stream_type_t streamDst)336 status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
337 {
338 auto srcCurves = getVolumeCurvesForStreamType(streamSrc);
339 auto dstCurves = getVolumeCurvesForStreamType(streamDst);
340
341 if (srcCurves == nullptr || dstCurves == nullptr) {
342 return BAD_VALUE;
343 }
344 return dstCurves->switchCurvesFrom(*srcCurves);
345 }
346
restoreOriginVolumeCurve(audio_stream_type_t stream)347 status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream)
348 {
349 VolumeCurves *curves = getVolumeCurvesForStreamType(stream);
350 return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE;
351 }
352
getVolumeGroups() const353 VolumeGroupVector EngineBase::getVolumeGroups() const
354 {
355 VolumeGroupVector group;
356 for (const auto &iter : mVolumeGroups) {
357 group.push_back(iter.first);
358 }
359 return group;
360 }
361
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const362 volume_group_t EngineBase::getVolumeGroupForAttributes(
363 const audio_attributes_t &attr, bool fallbackOnDefault) const
364 {
365 return mProductStrategies.getVolumeGroupForAttributes(attr, fallbackOnDefault);
366 }
367
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const368 volume_group_t EngineBase::getVolumeGroupForStreamType(
369 audio_stream_type_t stream, bool fallbackOnDefault) const
370 {
371 return mProductStrategies.getVolumeGroupForStreamType(stream, fallbackOnDefault);
372 }
373
listAudioVolumeGroups(AudioVolumeGroupVector & groups) const374 status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
375 {
376 for (const auto &iter : mVolumeGroups) {
377 groups.push_back({iter.second->getName(), iter.second->getId(),
378 iter.second->getSupportedAttributes(), iter.second->getStreamTypes()});
379 }
380 return NO_ERROR;
381 }
382
383 namespace {
384 template <typename T>
setDevicesRoleForT(std::map<std::pair<T,device_role_t>,AudioDeviceTypeAddrVector> & tDevicesRoleMap,T t,device_role_t role,const AudioDeviceTypeAddrVector & devices,const std::string & logStr,std::function<bool (T)> p)385 status_t setDevicesRoleForT(
386 std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
387 T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
388 const std::string& logStr, std::function<bool(T)> p) {
389 if (!p(t)) {
390 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
391 return BAD_VALUE;
392 }
393
394 switch (role) {
395 case DEVICE_ROLE_PREFERRED: {
396 tDevicesRoleMap[std::make_pair(t, role)] = devices;
397 // The preferred devices and disabled devices are mutually exclusive. Once a device is added
398 // the a list, it must be removed from the other one.
399 const device_role_t roleToRemove = DEVICE_ROLE_DISABLED;
400 auto it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
401 if (it != tDevicesRoleMap.end()) {
402 it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
403 if (it->second.empty()) {
404 tDevicesRoleMap.erase(it);
405 }
406 }
407 } break;
408 case DEVICE_ROLE_DISABLED: {
409 auto it = tDevicesRoleMap.find(std::make_pair(t, role));
410 if (it != tDevicesRoleMap.end()) {
411 it->second = joinDeviceTypeAddrs(it->second, devices);
412 } else {
413 tDevicesRoleMap[std::make_pair(t, role)] = devices;
414 }
415
416 // The preferred devices and disabled devices are mutually exclusive. Once a device is added
417 // the a list, it must be removed from the other one.
418 const device_role_t roleToRemove = DEVICE_ROLE_PREFERRED;
419 it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
420 if (it != tDevicesRoleMap.end()) {
421 it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
422 if (it->second.empty()) {
423 tDevicesRoleMap.erase(it);
424 }
425 }
426 } break;
427 case DEVICE_ROLE_NONE:
428 // Intentionally fall-through as it is no need to set device role as none for a strategy.
429 default:
430 ALOGE("%s invalid role %d", __func__, role);
431 return BAD_VALUE;
432 }
433 return NO_ERROR;
434 }
435
436 template <typename T>
removeDevicesRoleForT(std::map<std::pair<T,device_role_t>,AudioDeviceTypeAddrVector> & tDevicesRoleMap,T t,device_role_t role,const AudioDeviceTypeAddrVector & devices,const std::string & logStr,std::function<bool (T)> p)437 status_t removeDevicesRoleForT(
438 std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
439 T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
440 const std::string& logStr, std::function<bool(T)> p) {
441 if (!p(t)) {
442 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
443 return BAD_VALUE;
444 }
445
446 switch (role) {
447 case DEVICE_ROLE_PREFERRED:
448 case DEVICE_ROLE_DISABLED: {
449 auto it = tDevicesRoleMap.find(std::make_pair(t, role));
450 if (it != tDevicesRoleMap.end()) {
451 it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
452 if (it->second.empty()) {
453 tDevicesRoleMap.erase(it);
454 }
455 }
456 } break;
457 case DEVICE_ROLE_NONE:
458 // Intentionally fall-through as it is not needed to set device role as none for a strategy.
459 default:
460 ALOGE("%s invalid role %d", __func__, role);
461 return BAD_VALUE;
462 }
463 return NO_ERROR;
464 }
465
466 template <typename T>
removeAllDevicesRoleForT(std::map<std::pair<T,device_role_t>,AudioDeviceTypeAddrVector> & tDevicesRoleMap,T t,device_role_t role,const std::string & logStr,std::function<bool (T)> p)467 status_t removeAllDevicesRoleForT(
468 std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
469 T t, device_role_t role, const std::string& logStr, std::function<bool(T)> p) {
470 if (!p(t)) {
471 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
472 return BAD_VALUE;
473 }
474
475 switch (role) {
476 case DEVICE_ROLE_PREFERRED:
477 case DEVICE_ROLE_DISABLED:
478 if (tDevicesRoleMap.erase(std::make_pair(t, role)) == 0) {
479 // no preferred/disabled device was set
480 return NAME_NOT_FOUND;
481 }
482 break;
483 case DEVICE_ROLE_NONE:
484 // Intentionally fall-through as it makes no sense to remove devices with
485 // role as DEVICE_ROLE_NONE
486 default:
487 ALOGE("%s invalid role %d", __func__, role);
488 return BAD_VALUE;
489 }
490 return NO_ERROR;
491 }
492
493 template <typename T>
getDevicesRoleForT(const std::map<std::pair<T,device_role_t>,AudioDeviceTypeAddrVector> & tDevicesRoleMap,T t,device_role_t role,AudioDeviceTypeAddrVector & devices,const std::string & logStr,std::function<bool (T)> p)494 status_t getDevicesRoleForT(
495 const std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
496 T t, device_role_t role, AudioDeviceTypeAddrVector &devices, const std::string& logStr,
497 std::function<bool(T)> p) {
498 if (!p(t)) {
499 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
500 return BAD_VALUE;
501 }
502
503 switch (role) {
504 case DEVICE_ROLE_PREFERRED:
505 case DEVICE_ROLE_DISABLED: {
506 auto it = tDevicesRoleMap.find(std::make_pair(t, role));
507 if (it == tDevicesRoleMap.end()) {
508 ALOGV("%s no device as role %u for %s %u", __func__, role, logStr.c_str(), t);
509 return NAME_NOT_FOUND;
510 }
511
512 devices = it->second;
513 } break;
514 case DEVICE_ROLE_NONE:
515 // Intentionally fall-through as the DEVICE_ROLE_NONE is never set
516 default:
517 ALOGE("%s invalid role %d", __func__, role);
518 return BAD_VALUE;
519 }
520 return NO_ERROR;
521 }
522
523 } // namespace
524
setDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role,const AudioDeviceTypeAddrVector & devices)525 status_t EngineBase::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
526 const AudioDeviceTypeAddrVector &devices)
527 {
528 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
529 return mProductStrategies.find(strategy) != mProductStrategies.end();
530 };
531 return setDevicesRoleForT(
532 mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
533 }
534
removeDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role,const AudioDeviceTypeAddrVector & devices)535 status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
536 const AudioDeviceTypeAddrVector &devices)
537 {
538 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
539 return mProductStrategies.find(strategy) != mProductStrategies.end();
540 };
541 return removeDevicesRoleForT(
542 mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
543 }
544
clearDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role)545 status_t EngineBase::clearDevicesRoleForStrategy(product_strategy_t strategy,
546 device_role_t role)
547 {
548 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
549 return mProductStrategies.find(strategy) != mProductStrategies.end();
550 };
551 return removeAllDevicesRoleForT(
552 mProductStrategyDeviceRoleMap, strategy, role, "strategy" /*logStr*/, p);
553 }
554
getDevicesForRoleAndStrategy(product_strategy_t strategy,device_role_t role,AudioDeviceTypeAddrVector & devices) const555 status_t EngineBase::getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
556 AudioDeviceTypeAddrVector &devices) const
557 {
558 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
559 return mProductStrategies.find(strategy) != mProductStrategies.end();
560 };
561 return getDevicesRoleForT(
562 mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
563 }
564
setDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)565 status_t EngineBase::setDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
566 const AudioDeviceTypeAddrVector &devices)
567 {
568 std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
569 return audio_is_valid_audio_source(audioSource);
570 };
571 return setDevicesRoleForT(
572 mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
573 }
574
addDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)575 status_t EngineBase::addDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
576 const AudioDeviceTypeAddrVector &devices)
577 {
578 // verify if the audio source is valid
579 if (!audio_is_valid_audio_source(audioSource)) {
580 ALOGE("%s unknown audio source %u", __func__, audioSource);
581 }
582
583 switch (role) {
584 case DEVICE_ROLE_PREFERRED:
585 case DEVICE_ROLE_DISABLED: {
586 const auto audioSourceRole = std::make_pair(audioSource, role);
587 mCapturePresetDevicesRoleMap[audioSourceRole] = excludeDeviceTypeAddrsFrom(
588 mCapturePresetDevicesRoleMap[audioSourceRole], devices);
589 for (const auto &device : devices) {
590 mCapturePresetDevicesRoleMap[audioSourceRole].push_back(device);
591 }
592 // When the devices are set as preferred devices, remove them from the disabled devices.
593 doRemoveDevicesRoleForCapturePreset(
594 audioSource,
595 role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED : DEVICE_ROLE_PREFERRED,
596 devices,
597 false /*forceMatched*/);
598 } break;
599 case DEVICE_ROLE_NONE:
600 // Intentionally fall-through as it is no need to set device role as none
601 default:
602 ALOGE("%s invalid role %d", __func__, role);
603 return BAD_VALUE;
604 }
605 return NO_ERROR;
606 }
607
removeDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)608 status_t EngineBase::removeDevicesRoleForCapturePreset(
609 audio_source_t audioSource, device_role_t role, const AudioDeviceTypeAddrVector& devices) {
610 return doRemoveDevicesRoleForCapturePreset(audioSource, role, devices);
611 }
612
doRemoveDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices,bool forceMatched)613 status_t EngineBase::doRemoveDevicesRoleForCapturePreset(audio_source_t audioSource,
614 device_role_t role, const AudioDeviceTypeAddrVector& devices, bool forceMatched)
615 {
616 // verify if the audio source is valid
617 if (!audio_is_valid_audio_source(audioSource)) {
618 ALOGE("%s unknown audio source %u", __func__, audioSource);
619 }
620
621 switch (role) {
622 case DEVICE_ROLE_PREFERRED:
623 case DEVICE_ROLE_DISABLED: {
624 const auto audioSourceRole = std::make_pair(audioSource, role);
625 if (mCapturePresetDevicesRoleMap.find(audioSourceRole) ==
626 mCapturePresetDevicesRoleMap.end()) {
627 return NAME_NOT_FOUND;
628 }
629 AudioDeviceTypeAddrVector remainingDevices = excludeDeviceTypeAddrsFrom(
630 mCapturePresetDevicesRoleMap[audioSourceRole], devices);
631 if (forceMatched && remainingDevices.size() !=
632 mCapturePresetDevicesRoleMap[audioSourceRole].size() - devices.size()) {
633 // There are some devices from `devicesToRemove` that are not shown in the cached record
634 return BAD_VALUE;
635 }
636 mCapturePresetDevicesRoleMap[audioSourceRole] = remainingDevices;
637 if (mCapturePresetDevicesRoleMap[audioSourceRole].empty()) {
638 // Remove the role when device list is empty
639 mCapturePresetDevicesRoleMap.erase(audioSourceRole);
640 }
641 } break;
642 case DEVICE_ROLE_NONE:
643 // Intentionally fall-through as it makes no sense to remove devices with
644 // role as DEVICE_ROLE_NONE
645 default:
646 ALOGE("%s invalid role %d", __func__, role);
647 return BAD_VALUE;
648 }
649 return NO_ERROR;
650 }
651
clearDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role)652 status_t EngineBase::clearDevicesRoleForCapturePreset(audio_source_t audioSource,
653 device_role_t role)
654 {
655 std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
656 return audio_is_valid_audio_source(audioSource);
657 };
658 return removeAllDevicesRoleForT(
659 mCapturePresetDevicesRoleMap, audioSource, role, "audio source" /*logStr*/, p);
660 }
661
getDevicesForRoleAndCapturePreset(audio_source_t audioSource,device_role_t role,AudioDeviceTypeAddrVector & devices) const662 status_t EngineBase::getDevicesForRoleAndCapturePreset(audio_source_t audioSource,
663 device_role_t role, AudioDeviceTypeAddrVector &devices) const
664 {
665 std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
666 return audio_is_valid_audio_source(audioSource);
667 };
668 return getDevicesRoleForT(
669 mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
670 }
671
getMediaDevicesForRole(device_role_t role,const DeviceVector & availableDevices,DeviceVector & devices) const672 status_t EngineBase::getMediaDevicesForRole(device_role_t role,
673 const DeviceVector& availableDevices, DeviceVector& devices) const
674 {
675 product_strategy_t strategy = getProductStrategyByName("STRATEGY_MEDIA" /*name*/);
676 if (strategy == PRODUCT_STRATEGY_NONE) {
677 strategy = getProductStrategyForStream(AUDIO_STREAM_MUSIC);
678 }
679 if (strategy == PRODUCT_STRATEGY_NONE) {
680 return NAME_NOT_FOUND;
681 }
682 AudioDeviceTypeAddrVector deviceAddrVec;
683 status_t status = getDevicesForRoleAndStrategy(strategy, role, deviceAddrVec);
684 if (status != NO_ERROR) {
685 return status;
686 }
687 devices = availableDevices.getDevicesFromDeviceTypeAddrVec(deviceAddrVec);
688 return deviceAddrVec.size() == devices.size() ? NO_ERROR : NOT_ENOUGH_DATA;
689 }
690
getActiveMediaDevices(const DeviceVector & availableDevices) const691 DeviceVector EngineBase::getActiveMediaDevices(const DeviceVector& availableDevices) const
692 {
693 // The priority of active devices as follows:
694 // 1: the available preferred devices for media
695 // 2: the latest connected removable media device that is enabled
696 DeviceVector activeDevices;
697 if (getMediaDevicesForRole(
698 DEVICE_ROLE_PREFERRED, availableDevices, activeDevices) != NO_ERROR) {
699 activeDevices.clear();
700 DeviceVector disabledDevices;
701 getMediaDevicesForRole(DEVICE_ROLE_DISABLED, availableDevices, disabledDevices);
702 sp<DeviceDescriptor> device =
703 mLastRemovableMediaDevices.getLastRemovableMediaDevice(disabledDevices);
704 if (device != nullptr) {
705 activeDevices.add(device);
706 }
707 }
708 return activeDevices;
709 }
710
initializeDeviceSelectionCache()711 void EngineBase::initializeDeviceSelectionCache() {
712 // Initializing the device selection cache with default device won't be harmful, it will be
713 // updated after the audio modules are initialized.
714 auto defaultDevices = DeviceVector(getApmObserver()->getDefaultOutputDevice());
715 for (const auto &iter : getProductStrategies()) {
716 const auto &strategy = iter.second;
717 mDevicesForStrategies[strategy->getId()] = defaultDevices;
718 setStrategyDevices(strategy, defaultDevices);
719 }
720 }
721
updateDeviceSelectionCache()722 void EngineBase::updateDeviceSelectionCache() {
723 for (const auto &iter : getProductStrategies()) {
724 const auto& strategy = iter.second;
725 auto devices = getDevicesForProductStrategy(strategy->getId());
726 mDevicesForStrategies[strategy->getId()] = devices;
727 setStrategyDevices(strategy, devices);
728 }
729 }
730
getPreferredAvailableDevicesForProductStrategy(const DeviceVector & availableOutputDevices,product_strategy_t strategy) const731 DeviceVector EngineBase::getPreferredAvailableDevicesForProductStrategy(
732 const DeviceVector& availableOutputDevices, product_strategy_t strategy) const {
733 DeviceVector preferredAvailableDevVec = {};
734 AudioDeviceTypeAddrVector preferredStrategyDevices;
735 const status_t status = getDevicesForRoleAndStrategy(
736 strategy, DEVICE_ROLE_PREFERRED, preferredStrategyDevices);
737 if (status == NO_ERROR) {
738 // there is a preferred device, is it available?
739 preferredAvailableDevVec =
740 availableOutputDevices.getDevicesFromDeviceTypeAddrVec(preferredStrategyDevices);
741 if (preferredAvailableDevVec.size() == preferredStrategyDevices.size()) {
742 ALOGV("%s using pref device %s for strategy %u",
743 __func__, preferredAvailableDevVec.toString().c_str(), strategy);
744 return preferredAvailableDevVec;
745 }
746 }
747 return preferredAvailableDevVec;
748 }
749
getDisabledDevicesForProductStrategy(const DeviceVector & availableOutputDevices,product_strategy_t strategy) const750 DeviceVector EngineBase::getDisabledDevicesForProductStrategy(
751 const DeviceVector &availableOutputDevices, product_strategy_t strategy) const {
752 DeviceVector disabledDevices = {};
753 AudioDeviceTypeAddrVector disabledDevicesTypeAddr;
754 const status_t status = getDevicesForRoleAndStrategy(
755 strategy, DEVICE_ROLE_DISABLED, disabledDevicesTypeAddr);
756 if (status == NO_ERROR) {
757 disabledDevices =
758 availableOutputDevices.getDevicesFromDeviceTypeAddrVec(disabledDevicesTypeAddr);
759 }
760 return disabledDevices;
761 }
762
dumpCapturePresetDevicesRoleMap(String8 * dst,int spaces) const763 void EngineBase::dumpCapturePresetDevicesRoleMap(String8 *dst, int spaces) const
764 {
765 dst->appendFormat("\n%*sDevice role per capture preset dump:", spaces, "");
766 for (const auto& [capturePresetRolePair, devices] : mCapturePresetDevicesRoleMap) {
767 dst->appendFormat("\n%*sCapture preset(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
768 capturePresetRolePair.first, capturePresetRolePair.second,
769 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
770 }
771 dst->appendFormat("\n");
772 }
773
dump(String8 * dst) const774 void EngineBase::dump(String8 *dst) const
775 {
776 mProductStrategies.dump(dst, 2);
777 dumpProductStrategyDevicesRoleMap(mProductStrategyDeviceRoleMap, dst, 2);
778 dumpCapturePresetDevicesRoleMap(dst, 2);
779 mVolumeGroups.dump(dst, 2);
780 }
781
782 } // namespace audio_policy
783 } // namespace android
784