• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "APM::AudioPolicyEngine/Base"
18 //#define LOG_NDEBUG 0
19 
20 #include <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()118 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
119 {
120     auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
121         // Ensure name unicity to prevent duplicate
122         LOG_ALWAYS_FATAL_IF(std::any_of(std::begin(volumeGroups), std::end(volumeGroups),
123                                      [&volumeConfig](const auto &volumeGroup) {
124                 return volumeConfig.name == volumeGroup.second->getName(); }),
125                             "group name %s defined twice, review the configuration",
126                             volumeConfig.name.c_str());
127 
128         sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
129                                                       volumeConfig.indexMax);
130         volumeGroups[volumeGroup->getId()] = volumeGroup;
131 
132         for (auto &configCurve : volumeConfig.volumeCurves) {
133             device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
134             if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
135                 ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
136                 continue;
137             }
138             sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
139             for (auto &point : configCurve.curvePoints) {
140                 curve->add({point.index, point.attenuationInMb});
141             }
142             volumeGroup->add(curve);
143         }
144         return volumeGroup;
145     };
146     auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
147         for (const auto &attr : group.attributesVect) {
148             strategy->addAttributes({group.stream, volumeGroup->getId(), attr});
149             volumeGroup->addSupportedAttributes(attr);
150         }
151     };
152     auto checkStreamForGroups = [](auto streamType, const auto &volumeGroups) {
153         const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
154                                      [&streamType](const auto &volumeGroup) {
155             const auto& streams = volumeGroup.second->getStreamTypes();
156             return std::find(std::begin(streams), std::end(streams), streamType) !=
157                     std::end(streams);
158         });
159         return iter != end(volumeGroups);
160     };
161     auto fileExists = [](const char* path) {
162         struct stat fileStat;
163         return stat(path, &fileStat) == 0 && S_ISREG(fileStat.st_mode);
164     };
165 
166     auto result = fileExists(engineConfig::DEFAULT_PATH) ?
167             engineConfig::parse(engineConfig::DEFAULT_PATH) : engineConfig::ParsingResult{};
168     if (result.parsedConfig == nullptr) {
169         ALOGD("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
170         engineConfig::Config config = gDefaultEngineConfig;
171         android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
172         result = {std::make_unique<engineConfig::Config>(config),
173                   static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
174     } else {
175         // Append for internal use only volume groups (e.g. rerouting/patch)
176         result.parsedConfig->volumeGroups.insert(
177                     std::end(result.parsedConfig->volumeGroups),
178                     std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
179     }
180     // Append for internal use only strategies (e.g. rerouting/patch)
181     result.parsedConfig->productStrategies.insert(
182                 std::end(result.parsedConfig->productStrategies),
183                 std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
184 
185 
186     ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
187 
188     engineConfig::VolumeGroup defaultVolumeConfig;
189     engineConfig::VolumeGroup defaultSystemVolumeConfig;
190     for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
191         // save default volume config for streams not defined in configuration
192         if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
193             defaultVolumeConfig = volumeConfig;
194         }
195         if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {
196             defaultSystemVolumeConfig = volumeConfig;
197         }
198         loadVolumeConfig(mVolumeGroups, volumeConfig);
199     }
200     for (auto& strategyConfig : result.parsedConfig->productStrategies) {
201         sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
202         for (const auto &group : strategyConfig.attributesGroups) {
203             const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
204                                          [&group](const auto &volumeGroup) {
205                     return group.volumeGroup == volumeGroup.second->getName(); });
206             sp<VolumeGroup> volumeGroup = nullptr;
207             // If no volume group provided for this strategy, creates a new one using
208             // Music Volume Group configuration (considered as the default)
209             if (iter == end(mVolumeGroups)) {
210                 engineConfig::VolumeGroup volumeConfig;
211                 if (group.stream >= AUDIO_STREAM_PUBLIC_CNT) {
212                     volumeConfig = defaultSystemVolumeConfig;
213                 } else {
214                     volumeConfig = defaultVolumeConfig;
215                 }
216                 ALOGW("%s: No configuration of %s found, using default volume configuration"
217                         , __FUNCTION__, group.volumeGroup.c_str());
218                 volumeConfig.name = group.volumeGroup;
219                 volumeGroup = loadVolumeConfig(mVolumeGroups, volumeConfig);
220             } else {
221                 volumeGroup = iter->second;
222             }
223             if (group.stream != AUDIO_STREAM_DEFAULT) {
224                 // A legacy stream can be assigned once to a volume group
225                 LOG_ALWAYS_FATAL_IF(checkStreamForGroups(group.stream, mVolumeGroups),
226                                     "stream %s already assigned to a volume group, "
227                                     "review the configuration", toString(group.stream).c_str());
228                 volumeGroup->addSupportedStream(group.stream);
229             }
230             addSupportedAttributesToGroup(group, volumeGroup, strategy);
231         }
232         product_strategy_t strategyId = strategy->getId();
233         mProductStrategies[strategyId] = strategy;
234     }
235     mProductStrategies.initialize();
236     return result;
237 }
238 
getOrderedProductStrategies() const239 StrategyVector EngineBase::getOrderedProductStrategies() const
240 {
241     auto findByFlag = [](const auto &productStrategies, auto flag) {
242         return std::find_if(begin(productStrategies), end(productStrategies),
243                             [&](const auto &strategy) {
244             for (const auto &attributes : strategy.second->getAudioAttributes()) {
245                 if ((attributes.flags & flag) == flag) {
246                     return true;
247                 }
248             }
249             return false;
250         });
251     };
252     auto strategies = mProductStrategies;
253     auto enforcedAudibleStrategyIter = findByFlag(strategies, AUDIO_FLAG_AUDIBILITY_ENFORCED);
254 
255     if (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED &&
256             enforcedAudibleStrategyIter != strategies.end()) {
257         auto enforcedAudibleStrategy = *enforcedAudibleStrategyIter;
258         strategies.erase(enforcedAudibleStrategyIter);
259         strategies.insert(begin(strategies), enforcedAudibleStrategy);
260     }
261     StrategyVector orderedStrategies;
262     for (const auto &iter : strategies) {
263         orderedStrategies.push_back(iter.second->getId());
264     }
265     return orderedStrategies;
266 }
267 
getStreamTypesForProductStrategy(product_strategy_t ps) const268 StreamTypeVector EngineBase::getStreamTypesForProductStrategy(product_strategy_t ps) const
269 {
270     // @TODO default music stream to control volume if no group?
271     return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
272                 mProductStrategies.at(ps)->getSupportedStreams() :
273                 StreamTypeVector(AUDIO_STREAM_MUSIC);
274 }
275 
getAllAttributesForProductStrategy(product_strategy_t ps) const276 AttributesVector EngineBase::getAllAttributesForProductStrategy(product_strategy_t ps) const
277 {
278     return (mProductStrategies.find(ps) != end(mProductStrategies)) ?
279                 mProductStrategies.at(ps)->getAudioAttributes() : AttributesVector();
280 }
281 
listAudioProductStrategies(AudioProductStrategyVector & strategies) const282 status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &strategies) const
283 {
284     for (const auto &iter : mProductStrategies) {
285         const auto &productStrategy = iter.second;
286         strategies.push_back(
287         {productStrategy->getName(), productStrategy->listAudioAttributes(),
288          productStrategy->getId()});
289     }
290     return NO_ERROR;
291 }
292 
getVolumeCurvesForAttributes(const audio_attributes_t & attr) const293 VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const
294 {
295     volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr);
296     const auto &iter = mVolumeGroups.find(volGr);
297     LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str());
298     return mVolumeGroups.at(volGr)->getVolumeCurves();
299 }
300 
getVolumeCurvesForStreamType(audio_stream_type_t stream) const301 VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
302 {
303     volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
304     if (volGr == VOLUME_GROUP_NONE) {
305         volGr = mProductStrategies.getDefaultVolumeGroup();
306     }
307     const auto &iter = mVolumeGroups.find(volGr);
308     LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
309                 toString(stream).c_str());
310     return mVolumeGroups.at(volGr)->getVolumeCurves();
311 }
312 
switchVolumeCurve(audio_stream_type_t streamSrc,audio_stream_type_t streamDst)313 status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
314 {
315     auto srcCurves = getVolumeCurvesForStreamType(streamSrc);
316     auto dstCurves = getVolumeCurvesForStreamType(streamDst);
317 
318     if (srcCurves == nullptr || dstCurves == nullptr) {
319         return BAD_VALUE;
320     }
321     return dstCurves->switchCurvesFrom(*srcCurves);
322 }
323 
restoreOriginVolumeCurve(audio_stream_type_t stream)324 status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream)
325 {
326     VolumeCurves *curves = getVolumeCurvesForStreamType(stream);
327     return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE;
328 }
329 
getVolumeGroups() const330 VolumeGroupVector EngineBase::getVolumeGroups() const
331 {
332     VolumeGroupVector group;
333     for (const auto &iter : mVolumeGroups) {
334         group.push_back(iter.first);
335     }
336     return group;
337 }
338 
getVolumeGroupForAttributes(const audio_attributes_t & attr,bool fallbackOnDefault) const339 volume_group_t EngineBase::getVolumeGroupForAttributes(
340         const audio_attributes_t &attr, bool fallbackOnDefault) const
341 {
342     return mProductStrategies.getVolumeGroupForAttributes(attr, fallbackOnDefault);
343 }
344 
getVolumeGroupForStreamType(audio_stream_type_t stream,bool fallbackOnDefault) const345 volume_group_t EngineBase::getVolumeGroupForStreamType(
346         audio_stream_type_t stream, bool fallbackOnDefault) const
347 {
348     return mProductStrategies.getVolumeGroupForStreamType(stream, fallbackOnDefault);
349 }
350 
listAudioVolumeGroups(AudioVolumeGroupVector & groups) const351 status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
352 {
353     for (const auto &iter : mVolumeGroups) {
354         groups.push_back({iter.second->getName(), iter.second->getId(),
355                           iter.second->getSupportedAttributes(), iter.second->getStreamTypes()});
356     }
357     return NO_ERROR;
358 }
359 
360 namespace {
361 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)362 status_t setDevicesRoleForT(
363         std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
364         T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
365         const std::string& logStr, std::function<bool(T)> p) {
366     if (!p(t)) {
367         ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
368         return BAD_VALUE;
369     }
370 
371     switch (role) {
372     case DEVICE_ROLE_PREFERRED:
373     case DEVICE_ROLE_DISABLED: {
374         tDevicesRoleMap[std::make_pair(t, role)] = devices;
375         // The preferred devices and disabled devices are mutually exclusive. Once a device is added
376         // the a list, it must be removed from the other one.
377         const device_role_t roleToRemove = role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED
378                                                                          : DEVICE_ROLE_PREFERRED;
379         auto it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
380         if (it != tDevicesRoleMap.end()) {
381             it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
382             if (it->second.empty()) {
383                 tDevicesRoleMap.erase(it);
384             }
385         }
386     } break;
387     case DEVICE_ROLE_NONE:
388         // Intentionally fall-through as it is no need to set device role as none for a strategy.
389     default:
390         ALOGE("%s invalid role %d", __func__, role);
391         return BAD_VALUE;
392     }
393     return NO_ERROR;
394 }
395 
396 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)397 status_t removeAllDevicesRoleForT(
398         std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
399         T t, device_role_t role, const std::string& logStr, std::function<bool(T)> p) {
400     if (!p(t)) {
401         ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
402         return BAD_VALUE;
403     }
404 
405     switch (role) {
406     case DEVICE_ROLE_PREFERRED:
407     case DEVICE_ROLE_DISABLED:
408         if (tDevicesRoleMap.erase(std::make_pair(t, role)) == 0) {
409             // no preferred/disabled device was set
410             return NAME_NOT_FOUND;
411         }
412         break;
413     case DEVICE_ROLE_NONE:
414         // Intentionally fall-through as it makes no sense to remove devices with
415         // role as DEVICE_ROLE_NONE
416     default:
417         ALOGE("%s invalid role %d", __func__, role);
418         return BAD_VALUE;
419     }
420     return NO_ERROR;
421 }
422 
423 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)424 status_t getDevicesRoleForT(
425         const std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
426         T t, device_role_t role, AudioDeviceTypeAddrVector &devices, const std::string& logStr,
427         std::function<bool(T)> p) {
428     if (!p(t)) {
429         ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
430         return BAD_VALUE;
431     }
432 
433     switch (role) {
434     case DEVICE_ROLE_PREFERRED:
435     case DEVICE_ROLE_DISABLED: {
436         auto it = tDevicesRoleMap.find(std::make_pair(t, role));
437         if (it == tDevicesRoleMap.end()) {
438             ALOGV("%s no device as role %u for %s %u", __func__, role, logStr.c_str(), t);
439             return NAME_NOT_FOUND;
440         }
441 
442         devices = it->second;
443     } break;
444     case DEVICE_ROLE_NONE:
445         // Intentionally fall-through as the DEVICE_ROLE_NONE is never set
446     default:
447         ALOGE("%s invalid role %d", __func__, role);
448         return BAD_VALUE;
449     }
450     return NO_ERROR;
451 }
452 
453 } // namespace
454 
setDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role,const AudioDeviceTypeAddrVector & devices)455 status_t EngineBase::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
456             const AudioDeviceTypeAddrVector &devices)
457 {
458     std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
459         return mProductStrategies.find(strategy) != mProductStrategies.end();
460     };
461     return setDevicesRoleForT(
462             mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
463 }
464 
removeDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role)465 status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
466 {
467     std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
468         return mProductStrategies.find(strategy) != mProductStrategies.end();
469     };
470     return removeAllDevicesRoleForT(
471             mProductStrategyDeviceRoleMap, strategy, role, "strategy" /*logStr*/, p);
472 }
473 
getDevicesForRoleAndStrategy(product_strategy_t strategy,device_role_t role,AudioDeviceTypeAddrVector & devices) const474 status_t EngineBase::getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
475             AudioDeviceTypeAddrVector &devices) const
476 {
477     std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
478         return mProductStrategies.find(strategy) != mProductStrategies.end();
479     };
480     return getDevicesRoleForT(
481             mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
482 }
483 
setDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)484 status_t EngineBase::setDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
485         const AudioDeviceTypeAddrVector &devices)
486 {
487     std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
488         return audio_is_valid_audio_source(audioSource);
489     };
490     return setDevicesRoleForT(
491             mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
492 }
493 
addDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)494 status_t EngineBase::addDevicesRoleForCapturePreset(audio_source_t audioSource, device_role_t role,
495         const AudioDeviceTypeAddrVector &devices)
496 {
497     // verify if the audio source is valid
498     if (!audio_is_valid_audio_source(audioSource)) {
499         ALOGE("%s unknown audio source %u", __func__, audioSource);
500     }
501 
502     switch (role) {
503     case DEVICE_ROLE_PREFERRED:
504     case DEVICE_ROLE_DISABLED: {
505         const auto audioSourceRole = std::make_pair(audioSource, role);
506         mCapturePresetDevicesRoleMap[audioSourceRole] = excludeDeviceTypeAddrsFrom(
507                 mCapturePresetDevicesRoleMap[audioSourceRole], devices);
508         for (const auto &device : devices) {
509             mCapturePresetDevicesRoleMap[audioSourceRole].push_back(device);
510         }
511         // When the devices are set as preferred devices, remove them from the disabled devices.
512         doRemoveDevicesRoleForCapturePreset(
513                 audioSource,
514                 role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED : DEVICE_ROLE_PREFERRED,
515                 devices,
516                 false /*forceMatched*/);
517     } break;
518     case DEVICE_ROLE_NONE:
519         // Intentionally fall-through as it is no need to set device role as none
520     default:
521         ALOGE("%s invalid role %d", __func__, role);
522         return BAD_VALUE;
523     }
524     return NO_ERROR;
525 }
526 
removeDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices)527 status_t EngineBase::removeDevicesRoleForCapturePreset(
528         audio_source_t audioSource, device_role_t role, const AudioDeviceTypeAddrVector& devices) {
529     return doRemoveDevicesRoleForCapturePreset(audioSource, role, devices);
530 }
531 
doRemoveDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role,const AudioDeviceTypeAddrVector & devices,bool forceMatched)532 status_t EngineBase::doRemoveDevicesRoleForCapturePreset(audio_source_t audioSource,
533         device_role_t role, const AudioDeviceTypeAddrVector& devices, bool forceMatched)
534 {
535     // verify if the audio source is valid
536     if (!audio_is_valid_audio_source(audioSource)) {
537         ALOGE("%s unknown audio source %u", __func__, audioSource);
538     }
539 
540     switch (role) {
541     case DEVICE_ROLE_PREFERRED:
542     case DEVICE_ROLE_DISABLED: {
543         const auto audioSourceRole = std::make_pair(audioSource, role);
544         if (mCapturePresetDevicesRoleMap.find(audioSourceRole) ==
545                 mCapturePresetDevicesRoleMap.end()) {
546             return NAME_NOT_FOUND;
547         }
548         AudioDeviceTypeAddrVector remainingDevices = excludeDeviceTypeAddrsFrom(
549                 mCapturePresetDevicesRoleMap[audioSourceRole], devices);
550         if (forceMatched && remainingDevices.size() !=
551                 mCapturePresetDevicesRoleMap[audioSourceRole].size() - devices.size()) {
552             // There are some devices from `devicesToRemove` that are not shown in the cached record
553             return BAD_VALUE;
554         }
555         mCapturePresetDevicesRoleMap[audioSourceRole] = remainingDevices;
556         if (mCapturePresetDevicesRoleMap[audioSourceRole].empty()) {
557             // Remove the role when device list is empty
558             mCapturePresetDevicesRoleMap.erase(audioSourceRole);
559         }
560     } break;
561     case DEVICE_ROLE_NONE:
562         // Intentionally fall-through as it makes no sense to remove devices with
563         // role as DEVICE_ROLE_NONE
564     default:
565         ALOGE("%s invalid role %d", __func__, role);
566         return BAD_VALUE;
567     }
568     return NO_ERROR;
569 }
570 
clearDevicesRoleForCapturePreset(audio_source_t audioSource,device_role_t role)571 status_t EngineBase::clearDevicesRoleForCapturePreset(audio_source_t audioSource,
572                                                       device_role_t role)
573 {
574     std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
575         return audio_is_valid_audio_source(audioSource);
576     };
577     return removeAllDevicesRoleForT(
578             mCapturePresetDevicesRoleMap, audioSource, role, "audio source" /*logStr*/, p);
579 }
580 
getDevicesForRoleAndCapturePreset(audio_source_t audioSource,device_role_t role,AudioDeviceTypeAddrVector & devices) const581 status_t EngineBase::getDevicesForRoleAndCapturePreset(audio_source_t audioSource,
582         device_role_t role, AudioDeviceTypeAddrVector &devices) const
583 {
584     std::function<bool(audio_source_t)> p = [](audio_source_t audioSource) {
585         return audio_is_valid_audio_source(audioSource);
586     };
587     return getDevicesRoleForT(
588             mCapturePresetDevicesRoleMap, audioSource, role, devices, "audio source" /*logStr*/, p);
589 }
590 
getMediaDevicesForRole(device_role_t role,const DeviceVector & availableDevices,DeviceVector & devices) const591 status_t EngineBase::getMediaDevicesForRole(device_role_t role,
592         const DeviceVector& availableDevices, DeviceVector& devices) const
593 {
594     product_strategy_t strategy = getProductStrategyByName("STRATEGY_MEDIA" /*name*/);
595     if (strategy == PRODUCT_STRATEGY_NONE) {
596         strategy = getProductStrategyForStream(AUDIO_STREAM_MUSIC);
597     }
598     if (strategy == PRODUCT_STRATEGY_NONE) {
599         return NAME_NOT_FOUND;
600     }
601     AudioDeviceTypeAddrVector deviceAddrVec;
602     status_t status = getDevicesForRoleAndStrategy(strategy, role, deviceAddrVec);
603     if (status != NO_ERROR) {
604         return status;
605     }
606     devices = availableDevices.getDevicesFromDeviceTypeAddrVec(deviceAddrVec);
607     return deviceAddrVec.size() == devices.size() ? NO_ERROR : NOT_ENOUGH_DATA;
608 }
609 
getActiveMediaDevices(const DeviceVector & availableDevices) const610 DeviceVector EngineBase::getActiveMediaDevices(const DeviceVector& availableDevices) const
611 {
612     // The priority of active devices as follows:
613     // 1: the available preferred devices for media
614     // 2: the latest connected removable media device that is enabled
615     DeviceVector activeDevices;
616     if (getMediaDevicesForRole(
617             DEVICE_ROLE_PREFERRED, availableDevices, activeDevices) != NO_ERROR) {
618         activeDevices.clear();
619         DeviceVector disabledDevices;
620         getMediaDevicesForRole(DEVICE_ROLE_DISABLED, availableDevices, disabledDevices);
621         sp<DeviceDescriptor> device =
622                 mLastRemovableMediaDevices.getLastRemovableMediaDevice(disabledDevices);
623         if (device != nullptr) {
624             activeDevices.add(device);
625         }
626     }
627     return activeDevices;
628 }
629 
dumpCapturePresetDevicesRoleMap(String8 * dst,int spaces) const630 void EngineBase::dumpCapturePresetDevicesRoleMap(String8 *dst, int spaces) const
631 {
632     dst->appendFormat("\n%*sDevice role per capture preset dump:", spaces, "");
633     for (const auto& [capturePresetRolePair, devices] : mCapturePresetDevicesRoleMap) {
634         dst->appendFormat("\n%*sCapture preset(%u) Device Role(%u) Devices(%s)", spaces + 2, "",
635                 capturePresetRolePair.first, capturePresetRolePair.second,
636                 dumpAudioDeviceTypeAddrVector(devices, true /*includeSensitiveInfo*/).c_str());
637     }
638     dst->appendFormat("\n");
639 }
640 
dump(String8 * dst) const641 void EngineBase::dump(String8 *dst) const
642 {
643     mProductStrategies.dump(dst, 2);
644     dumpProductStrategyDevicesRoleMap(mProductStrategyDeviceRoleMap, dst, 2);
645     dumpCapturePresetDevicesRoleMap(dst, 2);
646     mVolumeGroups.dump(dst, 2);
647 }
648 
649 } // namespace audio_policy
650 } // namespace android
651