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