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