|  | /* | 
|  | * Copyright (C) 2015 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #define LOG_TAG "APM::AudioPolicyEngine" | 
|  | //#define LOG_NDEBUG 0 | 
|  |  | 
|  | //#define VERY_VERBOSE_LOGGING | 
|  | #ifdef VERY_VERBOSE_LOGGING | 
|  | #define ALOGVV ALOGV | 
|  | #else | 
|  | #define ALOGVV(a...) do { } while(0) | 
|  | #endif | 
|  |  | 
|  | #include "Engine.h" | 
|  | #include "Stream.h" | 
|  | #include "InputSource.h" | 
|  |  | 
|  | #include <EngineConfig.h> | 
|  | #include <policy.h> | 
|  | #include <AudioIODescriptorInterface.h> | 
|  | #include <ParameterManagerWrapper.h> | 
|  | #include <media/AudioContainers.h> | 
|  |  | 
|  | #include <media/TypeConverter.h> | 
|  |  | 
|  | #include <cinttypes> | 
|  |  | 
|  | using std::string; | 
|  | using std::map; | 
|  |  | 
|  | namespace android { | 
|  | namespace audio_policy { | 
|  |  | 
|  | template <> | 
|  | StreamCollection &Engine::getCollection<audio_stream_type_t>() | 
|  | { | 
|  | return mStreamCollection; | 
|  | } | 
|  | template <> | 
|  | InputSourceCollection &Engine::getCollection<audio_source_t>() | 
|  | { | 
|  | return mInputSourceCollection; | 
|  | } | 
|  |  | 
|  | template <> | 
|  | const StreamCollection &Engine::getCollection<audio_stream_type_t>() const | 
|  | { | 
|  | return mStreamCollection; | 
|  | } | 
|  | template <> | 
|  | const InputSourceCollection &Engine::getCollection<audio_source_t>() const | 
|  | { | 
|  | return mInputSourceCollection; | 
|  | } | 
|  |  | 
|  | Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper()) | 
|  | { | 
|  | } | 
|  |  | 
|  | status_t Engine::loadFromHalConfigWithFallback( | 
|  | const media::audio::common::AudioHalEngineConfig& config __unused) { | 
|  | // b/242678729. Need to implement for the configurable engine. | 
|  | return INVALID_OPERATION; | 
|  | } | 
|  |  | 
|  | status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath) | 
|  | { | 
|  | status_t loadResult = loadAudioPolicyEngineConfig(xmlFilePath); | 
|  | if (loadResult < 0) { | 
|  | ALOGE("Policy Engine configuration is invalid."); | 
|  | } | 
|  | return loadResult; | 
|  | } | 
|  |  | 
|  | status_t Engine::initCheck() | 
|  | { | 
|  | std::string error; | 
|  | if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) { | 
|  | ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str()); | 
|  | return NO_INIT; | 
|  | } | 
|  | return EngineBase::initCheck(); | 
|  | } | 
|  |  | 
|  | template <typename Key> | 
|  | Element<Key> *Engine::getFromCollection(const Key &key) const | 
|  | { | 
|  | const Collection<Key> &collection = getCollection<Key>(); | 
|  | return collection.get(key); | 
|  | } | 
|  |  | 
|  | template <typename Key> | 
|  | status_t Engine::add(const std::string &name, const Key &key) | 
|  | { | 
|  | Collection<Key> &collection = getCollection<Key>(); | 
|  | return collection.add(name, key); | 
|  | } | 
|  |  | 
|  | template <typename Property, typename Key> | 
|  | Property Engine::getPropertyForKey(Key key) const | 
|  | { | 
|  | Element<Key> *element = getFromCollection<Key>(key); | 
|  | if (element == NULL) { | 
|  | ALOGE("%s: Element not found within collection", __FUNCTION__); | 
|  | return static_cast<Property>(0); | 
|  | } | 
|  | return element->template get<Property>(); | 
|  | } | 
|  |  | 
|  | bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream, | 
|  | const audio_stream_type_t &profile) | 
|  | { | 
|  | if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) { | 
|  | switchVolumeCurve(profile, stream); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | template <typename Property, typename Key> | 
|  | bool Engine::setPropertyForKey(const Property &property, const Key &key) | 
|  | { | 
|  | Element<Key> *element = getFromCollection<Key>(key); | 
|  | if (element == NULL) { | 
|  | ALOGE("%s: Element not found within collection", __FUNCTION__); | 
|  | return false; | 
|  | } | 
|  | return element->template set<Property>(property) == NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t Engine::setPhoneState(audio_mode_t mode) | 
|  | { | 
|  | status_t status = mPolicyParameterMgr->setPhoneState(mode); | 
|  | if (status != NO_ERROR) { | 
|  | return status; | 
|  | } | 
|  | return EngineBase::setPhoneState(mode); | 
|  | } | 
|  |  | 
|  | audio_mode_t Engine::getPhoneState() const | 
|  | { | 
|  | return mPolicyParameterMgr->getPhoneState(); | 
|  | } | 
|  |  | 
|  | status_t Engine::setForceUse(audio_policy_force_use_t usage, | 
|  | audio_policy_forced_cfg_t config) | 
|  | { | 
|  | status_t status = mPolicyParameterMgr->setForceUse(usage, config); | 
|  | if (status != NO_ERROR) { | 
|  | return status; | 
|  | } | 
|  | return EngineBase::setForceUse(usage, config); | 
|  | } | 
|  |  | 
|  | audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const | 
|  | { | 
|  | return mPolicyParameterMgr->getForceUse(usage); | 
|  | } | 
|  |  | 
|  | status_t Engine::setOutputDevicesConnectionState(const DeviceVector &devices, | 
|  | audio_policy_dev_state_t state) | 
|  | { | 
|  | for (const auto &device : devices) { | 
|  | mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state); | 
|  | } | 
|  | DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
|  | if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) { | 
|  | availableOutputDevices.remove(devices); | 
|  | } else { | 
|  | availableOutputDevices.add(devices); | 
|  | } | 
|  | return mPolicyParameterMgr->setAvailableOutputDevices(availableOutputDevices.types()); | 
|  | } | 
|  |  | 
|  | status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device, | 
|  | audio_policy_dev_state_t state) | 
|  | { | 
|  | mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state); | 
|  | if (audio_is_output_device(device->type())) { | 
|  | return mPolicyParameterMgr->setAvailableOutputDevices( | 
|  | getApmObserver()->getAvailableOutputDevices().types()); | 
|  | } else if (audio_is_input_device(device->type())) { | 
|  | return mPolicyParameterMgr->setAvailableInputDevices( | 
|  | getApmObserver()->getAvailableInputDevices().types()); | 
|  | } | 
|  | return EngineBase::setDeviceConnectionState(device, state); | 
|  | } | 
|  |  | 
|  | status_t Engine::loadAudioPolicyEngineConfig(const std::string& xmlFilePath) | 
|  | { | 
|  | auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath); | 
|  |  | 
|  | // Custom XML Parsing | 
|  | auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) { | 
|  | for (auto& criterion : configCriteria) { | 
|  | engineConfig::CriterionType criterionType; | 
|  | for (auto &configCriterionType : configCriterionTypes) { | 
|  | if (configCriterionType.name == criterion.typeName) { | 
|  | criterionType = configCriterionType; | 
|  | break; | 
|  | } | 
|  | } | 
|  | ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s", | 
|  | criterion.name.c_str()); | 
|  | mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive, | 
|  | criterionType.valuePairs, | 
|  | criterion.defaultLiteralValue); | 
|  | } | 
|  | }; | 
|  |  | 
|  | loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes); | 
|  | return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE; | 
|  | } | 
|  |  | 
|  | status_t Engine::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role, | 
|  | const AudioDeviceTypeAddrVector &devices) | 
|  | { | 
|  | DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
|  | DeviceVector prevDisabledDevices = | 
|  | getDisabledDevicesForProductStrategy(availableOutputDevices, strategy); | 
|  | status_t status = EngineBase::setDevicesRoleForStrategy(strategy, role, devices); | 
|  | if (status != NO_ERROR) { | 
|  | return status; | 
|  | } | 
|  | DeviceVector newDisabledDevices = | 
|  | getDisabledDevicesForProductStrategy(availableOutputDevices, strategy); | 
|  | if (role == DEVICE_ROLE_PREFERRED) { | 
|  | DeviceVector reenabledDevices = prevDisabledDevices; | 
|  | reenabledDevices.remove(newDisabledDevices); | 
|  | if (reenabledDevices.empty()) { | 
|  | ALOGD("%s DEVICE_ROLE_PREFERRED empty renabled devices", __func__); | 
|  | return status; | 
|  | } | 
|  | // some devices were moved from disabled to preferred, need to force a resync for these | 
|  | enableDevicesForStrategy(strategy, prevDisabledDevices); | 
|  | } | 
|  | if (newDisabledDevices.empty()) { | 
|  | return status; | 
|  | } | 
|  | return disableDevicesForStrategy(strategy, newDisabledDevices); | 
|  | } | 
|  |  | 
|  | status_t Engine::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role, | 
|  | const AudioDeviceTypeAddrVector &devices) | 
|  | { | 
|  | const auto productStrategies = getProductStrategies(); | 
|  | if (productStrategies.find(strategy) == end(productStrategies)) { | 
|  | ALOGE("%s invalid %d", __func__, strategy); | 
|  | return BAD_VALUE; | 
|  | } | 
|  | DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
|  | DeviceVector prevDisabledDevices = | 
|  | getDisabledDevicesForProductStrategy(availableOutputDevices, strategy); | 
|  | status_t status = EngineBase::removeDevicesRoleForStrategy(strategy, role, devices); | 
|  | if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED) { | 
|  | return status; | 
|  | } | 
|  | // Removing ROLE_DISABLED for given devices, need to force a resync for these | 
|  | enableDevicesForStrategy(strategy, prevDisabledDevices); | 
|  |  | 
|  | DeviceVector remainingDisabledDevices = getDisabledDevicesForProductStrategy( | 
|  | availableOutputDevices, strategy); | 
|  | if (remainingDisabledDevices.empty()) { | 
|  | return status; | 
|  | } | 
|  | return disableDevicesForStrategy(strategy, remainingDisabledDevices); | 
|  | } | 
|  |  | 
|  | status_t Engine::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) | 
|  | { | 
|  | const auto productStrategies = getProductStrategies(); | 
|  | if (productStrategies.find(strategy) == end(productStrategies)) { | 
|  | ALOGE("%s invalid %d", __func__, strategy); | 
|  | return BAD_VALUE; | 
|  | } | 
|  | DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
|  | DeviceVector prevDisabledDevices = | 
|  | getDisabledDevicesForProductStrategy(availableOutputDevices, strategy); | 
|  | status_t status = EngineBase::clearDevicesRoleForStrategy(strategy, role); | 
|  | if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED || prevDisabledDevices.empty()) { | 
|  | return status; | 
|  | } | 
|  | // Disabled devices were removed, need to force a resync for these | 
|  | enableDevicesForStrategy(strategy, prevDisabledDevices); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | void Engine::enableDevicesForStrategy(product_strategy_t strategy __unused, | 
|  | const DeviceVector &devicesToEnable) { | 
|  | // devices were (re)enabled, need to force a resync for these | 
|  | setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE); | 
|  | setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE); | 
|  | } | 
|  |  | 
|  | status_t Engine::disableDevicesForStrategy(product_strategy_t strategy, | 
|  | const DeviceVector &devicesToDisable) { | 
|  | // Filter out disabled devices for this strategy. | 
|  | // However, to update the output device decision, availability criterion shall be updated, | 
|  | // which may impact other strategies. So, as a WA, reconsider now and later to prevent from | 
|  | // altering decision for other strategies; | 
|  | setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE); | 
|  |  | 
|  | DeviceTypeSet deviceTypes = getProductStrategies().getDeviceTypesForProductStrategy(strategy); | 
|  | const std::string address(getProductStrategies().getDeviceAddressForProductStrategy(strategy)); | 
|  |  | 
|  | setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE); | 
|  |  | 
|  | // Force reapply devices for given strategy | 
|  | getProductStrategies().at(strategy)->setDeviceTypes(deviceTypes); | 
|  | setDeviceAddressForProductStrategy(strategy, address); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const | 
|  | { | 
|  | DeviceVector selectedDevices = {}; | 
|  | DeviceVector disabledDevices = {}; | 
|  | const auto productStrategies = getProductStrategies(); | 
|  | if (productStrategies.find(ps) == productStrategies.end()) { | 
|  | ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps); | 
|  | return selectedDevices; | 
|  | } | 
|  | DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
|  | const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); | 
|  | DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types(); | 
|  |  | 
|  | // check if this strategy has a preferred device that is available, | 
|  | // if yes, give priority to it. | 
|  | DeviceVector preferredAvailableDevVec = | 
|  | getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps); | 
|  | if (!preferredAvailableDevVec.isEmpty()) { | 
|  | return preferredAvailableDevVec; | 
|  | } | 
|  |  | 
|  | /** This is the only case handled programmatically because the PFW is unable to know the | 
|  | * activity of streams. | 
|  | * | 
|  | * -While media is playing on a remote device, use the the sonification behavior. | 
|  | * Note that we test this usecase before testing if media is playing because | 
|  | * the isStreamActive() method only informs about the activity of a stream, not | 
|  | * if it's for local playback. Note also that we use the same delay between both tests | 
|  | * | 
|  | * -When media is not playing anymore, fall back on the sonification behavior | 
|  | */ | 
|  | DeviceTypeSet deviceTypes; | 
|  | product_strategy_t psOrFallback = ps; | 
|  | if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) && | 
|  | !is_state_in_call(getPhoneState()) && | 
|  | !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC), | 
|  | SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) && | 
|  | outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC), | 
|  | SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { | 
|  | psOrFallback = getProductStrategyForStream(AUDIO_STREAM_MUSIC); | 
|  | } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) && | 
|  | (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) || | 
|  | outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) { | 
|  | // do not route accessibility prompts to a digital output currently configured with a | 
|  | // compressed format as they would likely not be mixed and dropped. | 
|  | // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable. | 
|  | psOrFallback = getProductStrategyForStream(AUDIO_STREAM_RING); | 
|  | } | 
|  | disabledDevices = getDisabledDevicesForProductStrategy(availableOutputDevices, psOrFallback); | 
|  | deviceTypes = productStrategies.getDeviceTypesForProductStrategy(psOrFallback); | 
|  | // In case a fallback is decided on other strategy, prevent from selecting this device if | 
|  | // disabled for current strategy. | 
|  | availableOutputDevices.remove(disabledDevices); | 
|  |  | 
|  | if (deviceTypes.empty() || | 
|  | Intersection(deviceTypes, availableOutputDevicesTypes).empty()) { | 
|  | auto defaultDevice = getApmObserver()->getDefaultOutputDevice(); | 
|  | ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined"); | 
|  | selectedDevices = DeviceVector(defaultDevice); | 
|  | } else if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType( | 
|  | deviceTypes, AUDIO_DEVICE_OUT_BUS)) { | 
|  | // We do expect only one device for these types of devices | 
|  | // Criterion device address garantee this one is available | 
|  | // If this criterion is not wished, need to ensure this device is available | 
|  | const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str()); | 
|  | ALOGV("%s:device %s %s %d", | 
|  | __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps); | 
|  | auto busDevice = availableOutputDevices.getDevice( | 
|  | *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT); | 
|  | if (busDevice == nullptr) { | 
|  | ALOGE("%s:unavailable device %s %s, fallback on default", __func__, | 
|  | dumpDeviceTypes(deviceTypes).c_str(), address.c_str()); | 
|  | auto defaultDevice = getApmObserver()->getDefaultOutputDevice(); | 
|  | ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available"); | 
|  | selectedDevices = DeviceVector(defaultDevice); | 
|  | } else { | 
|  | selectedDevices = DeviceVector(busDevice); | 
|  | } | 
|  | } else { | 
|  | ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps); | 
|  | selectedDevices = availableOutputDevices.getDevicesFromTypes(deviceTypes); | 
|  | } | 
|  | return selectedDevices; | 
|  | } | 
|  |  | 
|  | DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes, | 
|  | const sp<DeviceDescriptor> &preferredDevice, | 
|  | bool fromCache) const | 
|  | { | 
|  | // First check for explict routing device | 
|  | if (preferredDevice != nullptr) { | 
|  | ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str()); | 
|  | return DeviceVector(preferredDevice); | 
|  | } | 
|  | product_strategy_t strategy = getProductStrategyForAttributes(attributes); | 
|  | const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
|  | const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); | 
|  | // | 
|  | // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to | 
|  | // be by APM? | 
|  | // | 
|  | // Honor explicit routing requests only if all active clients have a preferred route in which | 
|  | // case the last active client route is used | 
|  | sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices); | 
|  | if (device != nullptr) { | 
|  | return DeviceVector(device); | 
|  | } | 
|  | return fromCache? getCachedDevices(strategy) : getDevicesForProductStrategy(strategy); | 
|  | } | 
|  |  | 
|  | DeviceVector Engine::getCachedDevices(product_strategy_t ps) const | 
|  | { | 
|  | return mDevicesForStrategies.find(ps) != mDevicesForStrategies.end() ? | 
|  | mDevicesForStrategies.at(ps) : DeviceVector{}; | 
|  | } | 
|  |  | 
|  | DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const | 
|  | { | 
|  | auto attributes = EngineBase::getAttributesForStreamType(stream); | 
|  | return getOutputDevicesForAttributes(attributes, nullptr, fromCache); | 
|  | } | 
|  |  | 
|  | sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr, | 
|  | uid_t uid, | 
|  | audio_session_t session, | 
|  | sp<AudioPolicyMix> *mix) const | 
|  | { | 
|  | const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection(); | 
|  | const auto availableInputDevices = getApmObserver()->getAvailableInputDevices(); | 
|  | const auto &inputs = getApmObserver()->getInputs(); | 
|  | std::string address; | 
|  | // | 
|  | // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered | 
|  | // first as it used to be by APM? | 
|  | // | 
|  | // Honor explicit routing requests only if all active clients have a preferred route in which | 
|  | // case the last active client route is used | 
|  | sp<DeviceDescriptor> device = | 
|  | findPreferredDevice(inputs, attr.source, availableInputDevices); | 
|  | if (device != nullptr) { | 
|  | return device; | 
|  | } | 
|  |  | 
|  | device = policyMixes.getDeviceAndMixForInputSource(attr, | 
|  | availableInputDevices, | 
|  | uid, | 
|  | session, | 
|  | mix); | 
|  | if (device != nullptr) { | 
|  | return device; | 
|  | } | 
|  |  | 
|  | audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source); | 
|  |  | 
|  | if (audio_is_remote_submix_device(deviceType)) { | 
|  | address = "0"; | 
|  | std::size_t pos; | 
|  | std::string tags { attr.tags }; | 
|  | if ((pos = tags.find("addr=")) != std::string::npos) { | 
|  | address = tags.substr(pos + std::strlen("addr=")); | 
|  | } | 
|  | } | 
|  | return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT); | 
|  | } | 
|  |  | 
|  | void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy, | 
|  | const std::string &address) | 
|  | { | 
|  | if (getProductStrategies().find(strategy) == getProductStrategies().end()) { | 
|  | ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(), | 
|  | strategy); | 
|  | return; | 
|  | } | 
|  | getProductStrategies().at(strategy)->setDeviceAddress(address); | 
|  | } | 
|  |  | 
|  | bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, uint64_t devices) | 
|  | { | 
|  | if (getProductStrategies().find(strategy) == getProductStrategies().end()) { | 
|  | ALOGE("%s: set device %" PRId64 " on invalid strategy %d", __FUNCTION__, devices, strategy); | 
|  | return false; | 
|  | } | 
|  | // Here device matches the criterion value, need to rebuitd android device types; | 
|  | DeviceTypeSet types = | 
|  | mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(devices, true /*isOut*/); | 
|  | getProductStrategies().at(strategy)->setDeviceTypes(types); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Engine::setDeviceForInputSource(const audio_source_t &inputSource, uint64_t device) | 
|  | { | 
|  | DeviceTypeSet types = mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes( | 
|  | device, false /*isOut*/); | 
|  | ALOG_ASSERT(types.size() <= 1, "one input device expected at most"); | 
|  | audio_devices_t deviceType = types.empty() ? AUDIO_DEVICE_IN_DEFAULT : *types.begin(); | 
|  | return setPropertyForKey<audio_devices_t, audio_source_t>(deviceType, inputSource); | 
|  | } | 
|  |  | 
|  | template <> | 
|  | EngineInterface *Engine::queryInterface() | 
|  | { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | template <> | 
|  | AudioPolicyPluginInterface *Engine::queryInterface() | 
|  | { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | } // namespace audio_policy | 
|  | } // namespace android |