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 mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
76 }
77
78 return NO_ERROR;
79 }
80
getProductStrategyForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const81 product_strategy_t EngineBase::getProductStrategyForAttributes(
82 const audio_attributes_t &attr, bool fallbackOnDefault) const
83 {
84 return mProductStrategies.getProductStrategyForAttributes(attr, fallbackOnDefault);
85 }
86
getStreamTypeForAttributes(const audio_attributes_t & attr) const87 audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
88 {
89 return mProductStrategies.getStreamTypeForAttributes(attr);
90 }
91
getAttributesForStreamType(audio_stream_type_t stream) const92 audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const
93 {
94 return mProductStrategies.getAttributesForStreamType(stream);
95 }
96
getProductStrategyForStream(audio_stream_type_t stream) const97 product_strategy_t EngineBase::getProductStrategyForStream(audio_stream_type_t stream) const
98 {
99 return mProductStrategies.getProductStrategyForStream(stream);
100 }
101
getProductStrategyByName(const std::string & name) const102 product_strategy_t EngineBase::getProductStrategyByName(const std::string &name) const
103 {
104 for (const auto &iter : mProductStrategies) {
105 if (iter.second->getName() == name) {
106 return iter.second->getId();
107 }
108 }
109 return PRODUCT_STRATEGY_NONE;
110 }
111
loadAudioPolicyEngineConfig()112 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
113 {
114 auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
115 // Ensure name unicity to prevent duplicate
116 LOG_ALWAYS_FATAL_IF(std::any_of(std::begin(volumeGroups), std::end(volumeGroups),
117 [&volumeConfig](const auto &volumeGroup) {
118 return volumeConfig.name == volumeGroup.second->getName(); }),
119 "group name %s defined twice, review the configuration",
120 volumeConfig.name.c_str());
121
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 return volumeGroup;
139 };
140 auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
141 for (const auto &attr : group.attributesVect) {
142 strategy->addAttributes({group.stream, volumeGroup->getId(), attr});
143 volumeGroup->addSupportedAttributes(attr);
144 }
145 };
146 auto checkStreamForGroups = [](auto streamType, const auto &volumeGroups) {
147 const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
148 [&streamType](const auto &volumeGroup) {
149 const auto& streams = volumeGroup.second->getStreamTypes();
150 return std::find(std::begin(streams), std::end(streams), streamType) !=
151 std::end(streams);
152 });
153 return iter != end(volumeGroups);
154 };
155 auto fileExists = [](const char* path) {
156 struct stat fileStat;
157 return stat(path, &fileStat) == 0 && S_ISREG(fileStat.st_mode);
158 };
159
160 auto result = fileExists(engineConfig::DEFAULT_PATH) ?
161 engineConfig::parse(engineConfig::DEFAULT_PATH) : engineConfig::ParsingResult{};
162 if (result.parsedConfig == nullptr) {
163 ALOGD("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
164 engineConfig::Config config = gDefaultEngineConfig;
165 android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
166 result = {std::make_unique<engineConfig::Config>(config),
167 static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
168 } else {
169 // Append for internal use only volume groups (e.g. rerouting/patch)
170 result.parsedConfig->volumeGroups.insert(
171 std::end(result.parsedConfig->volumeGroups),
172 std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
173 }
174 // Append for internal use only strategies (e.g. rerouting/patch)
175 result.parsedConfig->productStrategies.insert(
176 std::end(result.parsedConfig->productStrategies),
177 std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
178
179
180 ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
181
182 engineConfig::VolumeGroup defaultVolumeConfig;
183 engineConfig::VolumeGroup defaultSystemVolumeConfig;
184 for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
185 // save default volume config for streams not defined in configuration
186 if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
187 defaultVolumeConfig = volumeConfig;
188 }
189 if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {
190 defaultSystemVolumeConfig = volumeConfig;
191 }
192 loadVolumeConfig(mVolumeGroups, volumeConfig);
193 }
194 for (auto& strategyConfig : result.parsedConfig->productStrategies) {
195 sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
196 for (const auto &group : strategyConfig.attributesGroups) {
197 const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
198 [&group](const auto &volumeGroup) {
199 return group.volumeGroup == volumeGroup.second->getName(); });
200 sp<VolumeGroup> volumeGroup = nullptr;
201 // If no volume group provided for this strategy, creates a new one using
202 // Music Volume Group configuration (considered as the default)
203 if (iter == end(mVolumeGroups)) {
204 engineConfig::VolumeGroup volumeConfig;
205 if (group.stream >= AUDIO_STREAM_PUBLIC_CNT) {
206 volumeConfig = defaultSystemVolumeConfig;
207 } else {
208 volumeConfig = defaultVolumeConfig;
209 }
210 ALOGW("%s: No configuration of %s found, using default volume configuration"
211 , __FUNCTION__, group.volumeGroup.c_str());
212 volumeConfig.name = group.volumeGroup;
213 volumeGroup = loadVolumeConfig(mVolumeGroups, volumeConfig);
214 } else {
215 volumeGroup = iter->second;
216 }
217 if (group.stream != AUDIO_STREAM_DEFAULT) {
218 // A legacy stream can be assigned once to a volume group
219 LOG_ALWAYS_FATAL_IF(checkStreamForGroups(group.stream, mVolumeGroups),
220 "stream %s already assigned to a volume group, "
221 "review the configuration", toString(group.stream).c_str());
222 volumeGroup->addSupportedStream(group.stream);
223 }
224 addSupportedAttributesToGroup(group, volumeGroup, strategy);
225 }
226 product_strategy_t strategyId = strategy->getId();
227 mProductStrategies[strategyId] = strategy;
228 }
229 mProductStrategies.initialize();
230 return result;
231 }
232
getOrderedProductStrategies() const233 StrategyVector EngineBase::getOrderedProductStrategies() const
234 {
235 auto findByFlag = [](const auto &productStrategies, auto flag) {
236 return std::find_if(begin(productStrategies), end(productStrategies),
237 [&](const auto &strategy) {
238 for (const auto &attributes : strategy.second->getAudioAttributes()) {
239 if ((attributes.flags & flag) == flag) {
240 return true;
241 }
242 }
243 return false;
244 });
245 };
246 auto strategies = mProductStrategies;
247 auto enforcedAudibleStrategyIter = findByFlag(strategies, AUDIO_FLAG_AUDIBILITY_ENFORCED);
248
249 if (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED &&
250 enforcedAudibleStrategyIter != strategies.end()) {
251 auto enforcedAudibleStrategy = *enforcedAudibleStrategyIter;
252 strategies.erase(enforcedAudibleStrategyIter);
253 strategies.insert(begin(strategies), enforcedAudibleStrategy);
254 }
255 StrategyVector orderedStrategies;
256 for (const auto &iter : strategies) {
257 orderedStrategies.push_back(iter.second->getId());
258 }
259 return orderedStrategies;
260 }
261
getStreamTypesForProductStrategy(product_strategy_t ps) const262 StreamTypeVector EngineBase::getStreamTypesForProductStrategy(product_strategy_t ps) const
263 {
264 // @TODO default music stream to control volume if no group?
265 return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
266 mProductStrategies.at(ps)->getSupportedStreams() :
267 StreamTypeVector(AUDIO_STREAM_MUSIC);
268 }
269
getAllAttributesForProductStrategy(product_strategy_t ps) const270 AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const
271 {
272 return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
273 mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector();
274 }
275
listAudioProductStrategies(AudioProductStrategyVector & strategies) const276 status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &strategies) const
277 {
278 for (const auto &iter : mProductStrategies) {
279 const auto &productStrategy = iter.second;
280 strategies.push_back(
281 {productStrategy->getName(), productStrategy->listAudioAttributes(),
282 productStrategy->getId()});
283 }
284 return NO_ERROR;
285 }
286
getVolumeCurvesForAttributes(const audio_attributes_t & attr) const287 VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const
288 {
289 volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr);
290 const auto &iter = mVolumeGroups.find(volGr);
291 LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str());
292 return mVolumeGroups.at(volGr)->getVolumeCurves();
293 }
294
getVolumeCurvesForStreamType(audio_stream_type_t stream) const295 VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
296 {
297 volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
298 if (volGr == VOLUME_GROUP_NONE) {
299 volGr = mProductStrategies.getDefaultVolumeGroup();
300 }
301 const auto &iter = mVolumeGroups.find(volGr);
302 LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
303 toString(stream).c_str());
304 return mVolumeGroups.at(volGr)->getVolumeCurves();
305 }
306
switchVolumeCurve(audio_stream_type_t streamSrc,audio_stream_type_t streamDst)307 status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
308 {
309 auto srcCurves = getVolumeCurvesForStreamType(streamSrc);
310 auto dstCurves = getVolumeCurvesForStreamType(streamDst);
311
312 if (srcCurves == nullptr || dstCurves == nullptr) {
313 return BAD_VALUE;
314 }
315 return dstCurves->switchCurvesFrom(*srcCurves);
316 }
317
restoreOriginVolumeCurve(audio_stream_type_t stream)318 status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream)
319 {
320 VolumeCurves *curves = getVolumeCurvesForStreamType(stream);
321 return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE;
322 }
323
getVolumeGroups() const324 VolumeGroupVector EngineBase::getVolumeGroups() const
325 {
326 VolumeGroupVector group;
327 for (const auto &iter : mVolumeGroups) {
328 group.push_back(iter.first);
329 }
330 return group;
331 }
332
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const333 volume_group_t EngineBase::getVolumeGroupForAttributes(
334 const audio_attributes_t &attr, bool fallbackOnDefault) const
335 {
336 return mProductStrategies.getVolumeGroupForAttributes(attr, fallbackOnDefault);
337 }
338
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const339 volume_group_t EngineBase::getVolumeGroupForStreamType(
340 audio_stream_type_t stream, bool fallbackOnDefault) const
341 {
342 return mProductStrategies.getVolumeGroupForStreamType(stream, fallbackOnDefault);
343 }
344
listAudioVolumeGroups(AudioVolumeGroupVector & groups) const345 status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
346 {
347 for (const auto &iter : mVolumeGroups) {
348 groups.push_back({iter.second->getName(), iter.second->getId(),
349 iter.second->getSupportedAttributes(), iter.second->getStreamTypes()});
350 }
351 return NO_ERROR;
352 }
353
354 namespace {
355 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)356 status_t setDevicesRoleForT(
357 std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
358 T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
359 const std::string& logStr, std::function<bool(T)> p) {
360 if (!p(t)) {
361 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
362 return BAD_VALUE;
363 }
364
365 switch (role) {
366 case DEVICE_ROLE_PREFERRED:
367 case DEVICE_ROLE_DISABLED: {
368 tDevicesRoleMap[std::make_pair(t, role)] = devices;
369 // The preferred devices and disabled devices are mutually exclusive. Once a device is added
370 // the a list, it must be removed from the other one.
371 const device_role_t roleToRemove = role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED
372 : DEVICE_ROLE_PREFERRED;
373 auto it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
374 if (it != tDevicesRoleMap.end()) {
375 it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
376 if (it->second.empty()) {
377 tDevicesRoleMap.erase(it);
378 }
379 }
380 } break;
381 case DEVICE_ROLE_NONE:
382 // Intentionally fall-through as it is no need to set device role as none for a strategy.
383 default:
384 ALOGE("%s invalid role %d", __func__, role);
385 return BAD_VALUE;
386 }
387 return NO_ERROR;
388 }
389
390 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)391 status_t removeAllDevicesRoleForT(
392 std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
393 T t, device_role_t role, const std::string& logStr, std::function<bool(T)> p) {
394 if (!p(t)) {
395 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
396 return BAD_VALUE;
397 }
398
399 switch (role) {
400 case DEVICE_ROLE_PREFERRED:
401 case DEVICE_ROLE_DISABLED:
402 if (tDevicesRoleMap.erase(std::make_pair(t, role)) == 0) {
403 // no preferred/disabled device was set
404 return NAME_NOT_FOUND;
405 }
406 break;
407 case DEVICE_ROLE_NONE:
408 // Intentionally fall-through as it makes no sense to remove devices with
409 // role as DEVICE_ROLE_NONE
410 default:
411 ALOGE("%s invalid role %d", __func__, role);
412 return BAD_VALUE;
413 }
414 return NO_ERROR;
415 }
416
417 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)418 status_t getDevicesRoleForT(
419 const std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
420 T t, device_role_t role, AudioDeviceTypeAddrVector &devices, const std::string& logStr,
421 std::function<bool(T)> p) {
422 if (!p(t)) {
423 ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
424 return BAD_VALUE;
425 }
426
427 switch (role) {
428 case DEVICE_ROLE_PREFERRED:
429 case DEVICE_ROLE_DISABLED: {
430 auto it = tDevicesRoleMap.find(std::make_pair(t, role));
431 if (it == tDevicesRoleMap.end()) {
432 ALOGV("%s no device as role %u for %s %u", __func__, role, logStr.c_str(), t);
433 return NAME_NOT_FOUND;
434 }
435
436 devices = it->second;
437 } break;
438 case DEVICE_ROLE_NONE:
439 // Intentionally fall-through as the DEVICE_ROLE_NONE is never set
440 default:
441 ALOGE("%s invalid role %d", __func__, role);
442 return BAD_VALUE;
443 }
444 return NO_ERROR;
445 }
446
447 } // namespace
448
setDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role,const AudioDeviceTypeAddrVector & devices)449 status_t EngineBase::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
450 const AudioDeviceTypeAddrVector &devices)
451 {
452 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
453 return mProductStrategies.find(strategy) != mProductStrategies.end();
454 };
455 return setDevicesRoleForT(
456 mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
457 }
458
removeDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role)459 status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
460 {
461 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
462 return mProductStrategies.find(strategy) != mProductStrategies.end();
463 };
464 return removeAllDevicesRoleForT(
465 mProductStrategyDeviceRoleMap, strategy, role, "strategy" /*logStr*/, p);
466 }
467
getDevicesForRoleAndStrategy(product_strategy_t strategy,device_role_t role,AudioDeviceTypeAddrVector & devices) const468 status_t EngineBase::getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
469 AudioDeviceTypeAddrVector &devices) const
470 {
471 std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
472 return mProductStrategies.find(strategy) != mProductStrategies.end();
473 };
474 return getDevicesRoleForT(
475 mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
476 }
477
setDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)478 status_t EngineBase::setDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
479 const AudioDeviceTypeAddrVector &devices)
480 {
481 std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
482 return audio_is_valid_audio_source(audioSource);
483 };
484 return setDevicesRoleForT(
485 mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
486 }
487
addDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)488 status_t EngineBase::addDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
489 const AudioDeviceTypeAddrVector &devices)
490 {
491 // verify if the audio source is valid
492 if (!audio_is_valid_audio_source(audioSource)) {
493 ALOGE("%s unknown audio source %u", __func__, audioSource);
494 }
495
496 switch (role) {
497 case DEVICE_ROLE_PREFERRED:
498 case DEVICE_ROLE_DISABLED: {
499 const auto audioSourceRole = std::make_pair(audioSource, role);
500 mCapturePresetDevicesRoleMap[audioSourceRole] = excludeDeviceTypeAddrsFrom(
501 mCapturePresetDevicesRoleMap[audioSourceRole], devices);
502 for (const auto &device : devices) {
503 mCapturePresetDevicesRoleMap[audioSourceRole].push_back(device);
504 }
505 // When the devices are set as preferred devices, remove them from the disabled devices.
506 doRemoveDevicesRoleForCapturePreset(
507 audioSource,
508 role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED : DEVICE_ROLE_PREFERRED,
509 devices,
510 false /*forceMatched*/);
511 } break;
512 case DEVICE_ROLE_NONE:
513 // Intentionally fall-through as it is no need to set device role as none
514 default:
515 ALOGE("%s invalid role %d", __func__, role);
516 return BAD_VALUE;
517 }
518 return NO_ERROR;
519 }
520
removeDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)521 status_t EngineBase::removeDevicesRoleForCapturePreset(
522 audio_source_t audioSource, device_role_t role, const AudioDeviceTypeAddrVector& devices) {
523 return doRemoveDevicesRoleForCapturePreset(audioSource, role, devices);
524 }
525
doRemoveDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices,bool forceMatched)526 status_t EngineBase::doRemoveDevicesRoleForCapturePreset(audio_source_t audioSource,
527 device_role_t role, const AudioDeviceTypeAddrVector& devices, bool forceMatched)
528 {
529 // verify if the audio source is valid
530 if (!audio_is_valid_audio_source(audioSource)) {
531 ALOGE("%s unknown audio source %u", __func__, audioSource);
532 }
533
534 switch (role) {
535 case DEVICE_ROLE_PREFERRED:
536 case DEVICE_ROLE_DISABLED: {
537 const auto audioSourceRole = std::make_pair(audioSource, role);
538 if (mCapturePresetDevicesRoleMap.find(audioSourceRole) ==
539 mCapturePresetDevicesRoleMap.end()) {
540 return NAME_NOT_FOUND;
541 }
542 AudioDeviceTypeAddrVector remainingDevices = excludeDeviceTypeAddrsFrom(
543 mCapturePresetDevicesRoleMap[audioSourceRole], devices);
544 if (forceMatched && remainingDevices.size() !=
545 mCapturePresetDevicesRoleMap[audioSourceRole].size() - devices.size()) {
546 // There are some devices from `devicesToRemove` that are not shown in the cached record
547 return BAD_VALUE;
548 }
549 mCapturePresetDevicesRoleMap[audioSourceRole] = remainingDevices;
550 if (mCapturePresetDevicesRoleMap[audioSourceRole].empty()) {
551 // Remove the role when device list is empty
552 mCapturePresetDevicesRoleMap.erase(audioSourceRole);
553 }
554 } break;
555 case DEVICE_ROLE_NONE:
556 // Intentionally fall-through as it makes no sense to remove devices with
557 // role as DEVICE_ROLE_NONE
558 default:
559 ALOGE("%s invalid role %d", __func__, role);
560 return BAD_VALUE;
561 }
562 return NO_ERROR;
563 }
564
clearDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role)565 status_t EngineBase::clearDevicesRoleForCapturePreset(audio_source_t audioSource,
566 device_role_t role)
567 {
568 std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
569 return audio_is_valid_audio_source(audioSource);
570 };
571 return removeAllDevicesRoleForT(
572 mCapturePresetDevicesRoleMap, audioSource, role, "audio source" /*logStr*/, p);
573 }
574
getDevicesForRoleAndCapturePreset(audio_source_t audioSource,device_role_t role,AudioDeviceTypeAddrVector & devices) const575 status_t EngineBase::getDevicesForRoleAndCapturePreset(audio_source_t audioSource,
576 device_role_t role, AudioDeviceTypeAddrVector &devices) const
577 {
578 std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
579 return audio_is_valid_audio_source(audioSource);
580 };
581 return getDevicesRoleForT(
582 mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
583 }
584
getMediaDevicesForRole(device_role_t role,const DeviceVector & availableDevices,DeviceVector & devices) const585 status_t EngineBase::getMediaDevicesForRole(device_role_t role,
586 const DeviceVector& availableDevices, DeviceVector& devices) const
587 {
588 product_strategy_t strategy = getProductStrategyByName("STRATEGY_MEDIA" /*name*/);
589 if (strategy == PRODUCT_STRATEGY_NONE) {
590 strategy = getProductStrategyForStream(AUDIO_STREAM_MUSIC);
591 }
592 if (strategy == PRODUCT_STRATEGY_NONE) {
593 return NAME_NOT_FOUND;
594 }
595 AudioDeviceTypeAddrVector deviceAddrVec;
596 status_t status = getDevicesForRoleAndStrategy(strategy, role, deviceAddrVec);
597 if (status != NO_ERROR) {
598 return status;
599 }
600 devices = availableDevices.getDevicesFromDeviceTypeAddrVec(deviceAddrVec);
601 return deviceAddrVec.size() == devices.size() ? NO_ERROR : NOT_ENOUGH_DATA;
602 }
603
getActiveMediaDevices(const DeviceVector & availableDevices) const604 DeviceVector EngineBase::getActiveMediaDevices(const DeviceVector& availableDevices) const
605 {
606 // The priority of active devices as follows:
607 // 1: the available preferred devices for media
608 // 2: the latest connected removable media device that is enabled
609 DeviceVector activeDevices;
610 if (getMediaDevicesForRole(
611 DEVICE_ROLE_PREFERRED, availableDevices, activeDevices) != NO_ERROR) {
612 activeDevices.clear();
613 DeviceVector disabledDevices;
614 getMediaDevicesForRole(DEVICE_ROLE_DISABLED, availableDevices, disabledDevices);
615 sp<DeviceDescriptor> device =
616 mLastRemovableMediaDevices.getLastRemovableMediaDevice(disabledDevices);
617 if (device != nullptr) {
618 activeDevices.add(device);
619 }
620 }
621 return activeDevices;
622 }
623
dumpCapturePresetDevicesRoleMap(String8 * dst,int spaces) const624 void EngineBase::dumpCapturePresetDevicesRoleMap(String8 *dst, int spaces) const
625 {
626 dst->appendFormat("\n%*sDevice role per capture preset dump:", spaces, "");
627 for (const auto& [capturePresetRolePair, devices] : mCapturePresetDevicesRoleMap) {
628 dst->appendFormat("\n%*sCapture preset(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
629 capturePresetRolePair.first, capturePresetRolePair.second,
630 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
631 }
632 dst->appendFormat("\n");
633 }
634
dump(String8 * dst) const635 void EngineBase::dump(String8 *dst) const
636 {
637 mProductStrategies.dump(dst, 2);
638 dumpProductStrategyDevicesRoleMap(mProductStrategyDeviceRoleMap, dst, 2);
639 dumpCapturePresetDevicesRoleMap(dst, 2);
640 mVolumeGroups.dump(dst, 2);
641 }
642
643 } // namespace audio_policy
644 } // namespace android
645