xref: /aosp_15_r20/frameworks/av/services/audiopolicy/engineconfigurable/src/Engine.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2015 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"
18 //#define LOG_NDEBUG 0
19 
20 //#define VERY_VERBOSE_LOGGING
21 #ifdef VERY_VERBOSE_LOGGING
22 #define ALOGVV ALOGV
23 #else
24 #define ALOGVV(a...) do { } while(0)
25 #endif
26 
27 #include "Engine.h"
28 #include "Stream.h"
29 #include "InputSource.h"
30 
31 #include <EngineConfig.h>
32 #include <policy.h>
33 #include <AudioIODescriptorInterface.h>
34 #include <ParameterManagerWrapper.h>
35 #include <media/AudioContainers.h>
36 
37 #include <media/TypeConverter.h>
38 
39 #include <cinttypes>
40 
41 using std::string;
42 using std::map;
43 
44 namespace android {
45 namespace audio_policy {
46 
47 template <>
getCollection()48 StreamCollection &Engine::getCollection<audio_stream_type_t>()
49 {
50     return mStreamCollection;
51 }
52 template <>
getCollection()53 InputSourceCollection &Engine::getCollection<audio_source_t>()
54 {
55     return mInputSourceCollection;
56 }
57 
58 template <>
getCollection() const59 const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
60 {
61     return mStreamCollection;
62 }
63 template <>
getCollection() const64 const InputSourceCollection &Engine::getCollection<audio_source_t>() const
65 {
66     return mInputSourceCollection;
67 }
68 
Engine()69 Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
70 {
71 }
72 
loadFromHalConfigWithFallback(const media::audio::common::AudioHalEngineConfig & aidlConfig)73 status_t Engine::loadFromHalConfigWithFallback(
74         const media::audio::common::AudioHalEngineConfig& aidlConfig) {
75 
76     auto capResult = capEngineConfig::convert(aidlConfig);
77     if (capResult.parsedConfig == nullptr) {
78         ALOGE("%s CapEngine Config invalid", __func__);
79         return BAD_VALUE;
80     }
81     status_t ret = loadWithFallback(aidlConfig);
82     if (ret != NO_ERROR) {
83         return ret;
84     }
85     auto loadCriteria= [this](const auto& capCriteria) {
86         for (auto& capCriterion : capCriteria) {
87             mPolicyParameterMgr->addCriterion(capCriterion.criterion.name,
88                     capCriterion.criterionType.isInclusive,
89                     capCriterion.criterionType.valuePairs,
90                     capCriterion.criterion.defaultLiteralValue);
91         }
92     };
93     loadCriteria(capResult.parsedConfig->capCriteria);
94     std::string error;
95     if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
96         ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
97         return NO_INIT;
98     }
99     return mPolicyParameterMgr->setConfiguration(capResult);
100 }
101 
loadFromXmlConfigWithFallback(const std::string & xmlFilePath)102 status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
103 {
104     status_t status = loadWithFallback(xmlFilePath);
105     std::string error;
106     if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
107         ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
108         return NO_INIT;
109     }
110     return status;
111 }
112 
113 template<typename T>
loadWithFallback(const T & configSource)114 status_t Engine::loadWithFallback(const T& configSource) {
115     auto result = EngineBase::loadAudioPolicyEngineConfig(configSource, true /*isConfigurable*/);
116     ALOGE_IF(result.nbSkippedElement != 0,
117              "Policy Engine configuration is partially invalid, skipped %zu elements",
118              result.nbSkippedElement);
119 
120     auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
121         for (auto& criterion : configCriteria) {
122             engineConfig::CriterionType criterionType;
123             for (auto &configCriterionType : configCriterionTypes) {
124                 if (configCriterionType.name == criterion.typeName) {
125                     criterionType = configCriterionType;
126                     break;
127                 }
128             }
129             ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
130                         criterion.name.c_str());
131             mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
132                                               criterionType.valuePairs,
133                                               criterion.defaultLiteralValue);
134         }
135     };
136 
137     loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
138     return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
139 }
140 
initCheck()141 status_t Engine::initCheck()
142 {
143     return EngineBase::initCheck();
144 }
145 
146 template <typename Key>
getFromCollection(const Key & key) const147 Element<Key> *Engine::getFromCollection(const Key &key) const
148 {
149     const Collection<Key> &collection = getCollection<Key>();
150     return collection.get(key);
151 }
152 
153 template <typename Key>
add(const std::string & name,const Key & key)154 status_t Engine::add(const std::string &name, const Key &key)
155 {
156     Collection<Key> &collection = getCollection<Key>();
157     return collection.add(name, key);
158 }
159 
160 template <typename Property, typename Key>
getPropertyForKey(Key key) const161 Property Engine::getPropertyForKey(Key key) const
162 {
163     Element<Key> *element = getFromCollection<Key>(key);
164     if (element == NULL) {
165         ALOGE("%s: Element not found within collection", __FUNCTION__);
166         return static_cast<Property>(0);
167     }
168     return element->template get<Property>();
169 }
170 
setVolumeProfileForStream(const audio_stream_type_t & stream,const audio_stream_type_t & profile)171 bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
172                                        const audio_stream_type_t &profile)
173 {
174     if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
175         switchVolumeCurve(profile, stream);
176         return true;
177     }
178     return false;
179 }
180 
181 template <typename Property, typename Key>
setPropertyForKey(const Property & property,const Key & key)182 bool Engine::setPropertyForKey(const Property &property, const Key &key)
183 {
184     Element<Key> *element = getFromCollection<Key>(key);
185     if (element == NULL) {
186         ALOGE("%s: Element not found within collection", __FUNCTION__);
187         return false;
188     }
189     return element->template set<Property>(property) == NO_ERROR;
190 }
191 
setPhoneState(audio_mode_t mode)192 status_t Engine::setPhoneState(audio_mode_t mode)
193 {
194     status_t status = mPolicyParameterMgr->setPhoneState(mode);
195     if (status != NO_ERROR) {
196         return status;
197     }
198     return EngineBase::setPhoneState(mode);
199 }
200 
getPhoneState() const201 audio_mode_t Engine::getPhoneState() const
202 {
203     return mPolicyParameterMgr->getPhoneState();
204 }
205 
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)206 status_t Engine::setForceUse(audio_policy_force_use_t usage,
207                                       audio_policy_forced_cfg_t config)
208 {
209     status_t status = mPolicyParameterMgr->setForceUse(usage, config);
210     if (status != NO_ERROR) {
211         return status;
212     }
213     return EngineBase::setForceUse(usage, config);
214 }
215 
getForceUse(audio_policy_force_use_t usage) const216 audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
217 {
218     return mPolicyParameterMgr->getForceUse(usage);
219 }
220 
setOutputDevicesConnectionState(const DeviceVector & devices,audio_policy_dev_state_t state)221 status_t Engine::setOutputDevicesConnectionState(const DeviceVector &devices,
222                                                  audio_policy_dev_state_t state)
223 {
224     for (const auto &device : devices) {
225         mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
226     }
227     DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
228     if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
229         availableOutputDevices.remove(devices);
230     } else {
231         availableOutputDevices.add(devices);
232     }
233     return mPolicyParameterMgr->setAvailableOutputDevices(availableOutputDevices.types());
234 }
235 
setDeviceConnectionState(const sp<DeviceDescriptor> device,audio_policy_dev_state_t state)236 status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
237                                           audio_policy_dev_state_t state)
238 {
239     mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
240     if (audio_is_output_device(device->type())) {
241         return mPolicyParameterMgr->setAvailableOutputDevices(
242                     getApmObserver()->getAvailableOutputDevices().types());
243     } else if (audio_is_input_device(device->type())) {
244         return mPolicyParameterMgr->setAvailableInputDevices(
245                     getApmObserver()->getAvailableInputDevices().types());
246     }
247     return EngineBase::setDeviceConnectionState(device, state);
248 }
249 
setDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role,const AudioDeviceTypeAddrVector & devices)250 status_t Engine::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
251                                            const AudioDeviceTypeAddrVector &devices)
252 {
253     DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
254     DeviceVector prevDisabledDevices =
255             getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
256     status_t status = EngineBase::setDevicesRoleForStrategy(strategy, role, devices);
257     if (status != NO_ERROR) {
258         return status;
259     }
260     DeviceVector newDisabledDevices =
261             getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
262     if (role == DEVICE_ROLE_PREFERRED) {
263         DeviceVector reenabledDevices = prevDisabledDevices;
264         reenabledDevices.remove(newDisabledDevices);
265         if (reenabledDevices.empty()) {
266             ALOGD("%s DEVICE_ROLE_PREFERRED empty renabled devices", __func__);
267             return status;
268         }
269         // some devices were moved from disabled to preferred, need to force a resync for these
270         enableDevicesForStrategy(strategy, prevDisabledDevices);
271     }
272     if (newDisabledDevices.empty()) {
273         return status;
274     }
275     return disableDevicesForStrategy(strategy, newDisabledDevices);
276 }
277 
removeDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role,const AudioDeviceTypeAddrVector & devices)278 status_t Engine::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
279         const AudioDeviceTypeAddrVector &devices)
280 {
281     const auto productStrategies = getProductStrategies();
282     if (productStrategies.find(strategy) == end(productStrategies)) {
283         ALOGE("%s invalid %d", __func__, strategy);
284         return BAD_VALUE;
285     }
286     DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
287     DeviceVector prevDisabledDevices =
288             getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
289     status_t status = EngineBase::removeDevicesRoleForStrategy(strategy, role, devices);
290     if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED) {
291         return status;
292     }
293     // Removing ROLE_DISABLED for given devices, need to force a resync for these
294     enableDevicesForStrategy(strategy, prevDisabledDevices);
295 
296     DeviceVector remainingDisabledDevices = getDisabledDevicesForProductStrategy(
297             availableOutputDevices, strategy);
298     if (remainingDisabledDevices.empty()) {
299         return status;
300     }
301     return disableDevicesForStrategy(strategy, remainingDisabledDevices);
302 }
303 
clearDevicesRoleForStrategy(product_strategy_t strategy,device_role_t role)304 status_t Engine::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
305 {
306     const auto productStrategies = getProductStrategies();
307     if (productStrategies.find(strategy) == end(productStrategies)) {
308         ALOGE("%s invalid %d", __func__, strategy);
309         return BAD_VALUE;
310     }
311     DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
312     DeviceVector prevDisabledDevices =
313             getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
314     status_t status = EngineBase::clearDevicesRoleForStrategy(strategy, role);
315     if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED || prevDisabledDevices.empty()) {
316         return status;
317     }
318     // Disabled devices were removed, need to force a resync for these
319     enableDevicesForStrategy(strategy, prevDisabledDevices);
320     return NO_ERROR;
321 }
322 
enableDevicesForStrategy(product_strategy_t strategy __unused,const DeviceVector & devicesToEnable)323 void Engine::enableDevicesForStrategy(product_strategy_t strategy __unused,
324         const DeviceVector &devicesToEnable) {
325     // devices were (re)enabled, need to force a resync for these
326     setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
327     setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
328 }
329 
disableDevicesForStrategy(product_strategy_t strategy,const DeviceVector & devicesToDisable)330 status_t Engine::disableDevicesForStrategy(product_strategy_t strategy,
331         const DeviceVector &devicesToDisable) {
332     // Filter out disabled devices for this strategy.
333     // However, to update the output device decision, availability criterion shall be updated,
334     // which may impact other strategies. So, as a WA, reconsider now and later to prevent from
335     // altering decision for other strategies;
336     setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
337 
338     DeviceTypeSet deviceTypes = getProductStrategies().getDeviceTypesForProductStrategy(strategy);
339     const std::string address(getProductStrategies().getDeviceAddressForProductStrategy(strategy));
340 
341     setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
342 
343     // Force reapply devices for given strategy
344     getProductStrategies().at(strategy)->setDeviceTypes(deviceTypes);
345     setDeviceAddressForProductStrategy(strategy, address);
346     return NO_ERROR;
347 }
348 
getDevicesForProductStrategy(product_strategy_t ps) const349 DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
350 {
351     DeviceVector selectedDevices = {};
352     DeviceVector disabledDevices = {};
353     const auto productStrategies = getProductStrategies();
354     if (productStrategies.find(ps) == productStrategies.end()) {
355         ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
356         return selectedDevices;
357     }
358     DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
359     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
360     DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
361 
362     // check if this strategy has a preferred device that is available,
363     // if yes, give priority to it.
364     DeviceVector preferredAvailableDevVec =
365             getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps);
366     if (!preferredAvailableDevVec.isEmpty()) {
367         return preferredAvailableDevVec;
368     }
369 
370     /** This is the only case handled programmatically because the PFW is unable to know the
371      * activity of streams.
372      *
373      * -While media is playing on a remote device, use the the sonification behavior.
374      * Note that we test this usecase before testing if media is playing because
375      * the isStreamActive() method only informs about the activity of a stream, not
376      * if it's for local playback. Note also that we use the same delay between both tests
377      *
378      * -When media is not playing anymore, fall back on the sonification behavior
379      */
380     DeviceTypeSet deviceTypes;
381     product_strategy_t psOrFallback = ps;
382     if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
383             !is_state_in_call(getPhoneState()) &&
384             !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
385                                       SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
386             outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
387                              SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
388         psOrFallback = getProductStrategyForStream(AUDIO_STREAM_MUSIC);
389     } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
390         (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
391          outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
392             // do not route accessibility prompts to a digital output currently configured with a
393             // compressed format as they would likely not be mixed and dropped.
394             // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
395         psOrFallback = getProductStrategyForStream(AUDIO_STREAM_RING);
396     }
397     disabledDevices = getDisabledDevicesForProductStrategy(availableOutputDevices, psOrFallback);
398     deviceTypes = productStrategies.getDeviceTypesForProductStrategy(psOrFallback);
399     // In case a fallback is decided on other strategy, prevent from selecting this device if
400     // disabled for current strategy.
401     availableOutputDevices.remove(disabledDevices);
402 
403     if (deviceTypes.empty() ||
404             Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
405         auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
406         ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
407         selectedDevices = DeviceVector(defaultDevice);
408     } else if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
409             deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
410         // We do expect only one device for these types of devices
411         // Criterion device address garantee this one is available
412         // If this criterion is not wished, need to ensure this device is available
413         const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
414         ALOGV("%s:device %s %s %d",
415                 __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
416         auto busDevice = availableOutputDevices.getDevice(
417                 *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
418         if (busDevice == nullptr) {
419             ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
420                   dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
421             auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
422             ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
423             selectedDevices = DeviceVector(defaultDevice);
424         } else {
425             selectedDevices = DeviceVector(busDevice);
426         }
427     } else {
428         ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
429         selectedDevices = availableOutputDevices.getDevicesFromTypes(deviceTypes);
430     }
431     return selectedDevices;
432 }
433 
getOutputDevicesForAttributes(const audio_attributes_t & attributes,const sp<DeviceDescriptor> & preferredDevice,bool fromCache) const434 DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
435                                                    const sp<DeviceDescriptor> &preferredDevice,
436                                                    bool fromCache) const
437 {
438     // First check for explict routing device
439     if (preferredDevice != nullptr) {
440         ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
441         return DeviceVector(preferredDevice);
442     }
443     product_strategy_t strategy = getProductStrategyForAttributes(attributes);
444     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
445     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
446     //
447     // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
448     // be by APM?
449     //
450     // Honor explicit routing requests only if all active clients have a preferred route in which
451     // case the last active client route is used
452     sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
453     if (device != nullptr) {
454         return DeviceVector(device);
455     }
456     return fromCache? getCachedDevices(strategy) : getDevicesForProductStrategy(strategy);
457 }
458 
getCachedDevices(product_strategy_t ps) const459 DeviceVector Engine::getCachedDevices(product_strategy_t ps) const
460 {
461     return mDevicesForStrategies.find(ps) != mDevicesForStrategies.end() ?
462                 mDevicesForStrategies.at(ps) : DeviceVector{};
463 }
464 
getOutputDevicesForStream(audio_stream_type_t stream,bool fromCache) const465 DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
466 {
467     auto attributes = EngineBase::getAttributesForStreamType(stream);
468     return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
469 }
470 
getInputDeviceForAttributes(const audio_attributes_t & attr,uid_t uid,audio_session_t session,sp<AudioPolicyMix> * mix) const471 sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
472                                                          uid_t uid,
473                                                          audio_session_t session,
474                                                          sp<AudioPolicyMix> *mix) const
475 {
476     const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
477     const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
478     const auto &inputs = getApmObserver()->getInputs();
479     std::string address;
480     //
481     // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
482     // first as it used to be by APM?
483     //
484     // Honor explicit routing requests only if all active clients have a preferred route in which
485     // case the last active client route is used
486     sp<DeviceDescriptor> device =
487             findPreferredDevice(inputs, attr.source, availableInputDevices);
488     if (device != nullptr) {
489         return device;
490     }
491 
492     device = policyMixes.getDeviceAndMixForInputSource(attr,
493                                                        availableInputDevices,
494                                                        uid,
495                                                        session,
496                                                        mix);
497     if (device != nullptr) {
498         return device;
499     }
500 
501     audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
502 
503     if (audio_is_remote_submix_device(deviceType)) {
504         address = "0";
505         std::size_t pos;
506         std::string tags { attr.tags };
507         if ((pos = tags.find("addr=")) != std::string::npos) {
508             address = tags.substr(pos + std::strlen("addr="));
509         }
510     }
511     return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
512 }
513 
setDeviceAddressForProductStrategy(product_strategy_t strategy,const std::string & address)514 void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
515                                                 const std::string &address)
516 {
517     if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
518         ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
519               strategy);
520         return;
521     }
522     getProductStrategies().at(strategy)->setDeviceAddress(address);
523 }
524 
setDeviceTypesForProductStrategy(product_strategy_t strategy,uint64_t devices)525 bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, uint64_t devices)
526 {
527     if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
528         ALOGE("%s: set device %" PRId64 " on invalid strategy %d", __FUNCTION__, devices, strategy);
529         return false;
530     }
531     // Here device matches the criterion value, need to rebuitd android device types;
532     DeviceTypeSet types =
533             mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(devices, true /*isOut*/);
534     getProductStrategies().at(strategy)->setDeviceTypes(types);
535     return true;
536 }
537 
setDeviceForInputSource(const audio_source_t & inputSource,uint64_t device)538 bool Engine::setDeviceForInputSource(const audio_source_t &inputSource, uint64_t device)
539 {
540     DeviceTypeSet types = mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(
541                 device, false /*isOut*/);
542     ALOG_ASSERT(types.size() <= 1, "one input device expected at most");
543     audio_devices_t deviceType = types.empty() ? AUDIO_DEVICE_IN_DEFAULT : *types.begin();
544     return setPropertyForKey<audio_devices_t, audio_source_t>(deviceType, inputSource);
545 }
546 
547 template <>
queryInterface()548 EngineInterface *Engine::queryInterface()
549 {
550     return this;
551 }
552 
553 template <>
queryInterface()554 AudioPolicyPluginInterface *Engine::queryInterface()
555 {
556     return this;
557 }
558 
559 } // namespace audio_policy
560 } // namespace android
561