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