| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 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" | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 28 | #include "Stream.h" | 
 | 29 | #include "InputSource.h" | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 30 |  | 
 | 31 | #include <EngineConfig.h> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 32 | #include <policy.h> | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 33 | #include <AudioIODescriptorInterface.h> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 34 | #include <ParameterManagerWrapper.h> | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 35 | #include <media/AudioContainers.h> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 36 |  | 
| François Gaffie | c60c369 | 2019-08-09 15:41:24 +0200 | [diff] [blame] | 37 | #include <media/TypeConverter.h> | 
 | 38 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 39 | using std::string; | 
 | 40 | using std::map; | 
 | 41 |  | 
| François Gaffie | f19cf79 | 2018-05-30 17:22:17 +0200 | [diff] [blame] | 42 | namespace android { | 
 | 43 | namespace audio_policy { | 
 | 44 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 45 | template <> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 46 | StreamCollection &Engine::getCollection<audio_stream_type_t>() | 
 | 47 | { | 
 | 48 |     return mStreamCollection; | 
 | 49 | } | 
 | 50 | template <> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 51 | InputSourceCollection &Engine::getCollection<audio_source_t>() | 
 | 52 | { | 
 | 53 |     return mInputSourceCollection; | 
 | 54 | } | 
 | 55 |  | 
 | 56 | template <> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 57 | const StreamCollection &Engine::getCollection<audio_stream_type_t>() const | 
 | 58 | { | 
 | 59 |     return mStreamCollection; | 
 | 60 | } | 
 | 61 | template <> | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 62 | const InputSourceCollection &Engine::getCollection<audio_source_t>() const | 
 | 63 | { | 
 | 64 |     return mInputSourceCollection; | 
 | 65 | } | 
 | 66 |  | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 67 | Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper()) | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 68 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 69 |     status_t loadResult = loadAudioPolicyEngineConfig(); | 
 | 70 |     if (loadResult < 0) { | 
 | 71 |         ALOGE("Policy Engine configuration is invalid."); | 
 | 72 |     } | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 73 | } | 
 | 74 |  | 
 | 75 | Engine::~Engine() | 
 | 76 | { | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 77 |     mStreamCollection.clear(); | 
 | 78 |     mInputSourceCollection.clear(); | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 79 | } | 
 | 80 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 81 | status_t Engine::initCheck() | 
 | 82 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 83 |     if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) { | 
| François Gaffie | 0f17ab7 | 2015-05-13 18:13:00 +0200 | [diff] [blame] | 84 |         ALOGE("%s: could not start Policy PFW", __FUNCTION__); | 
| François Gaffie | 0f17ab7 | 2015-05-13 18:13:00 +0200 | [diff] [blame] | 85 |         return NO_INIT; | 
 | 86 |     } | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 87 |     return EngineBase::initCheck(); | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 88 | } | 
 | 89 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 90 | template <typename Key> | 
 | 91 | Element<Key> *Engine::getFromCollection(const Key &key) const | 
 | 92 | { | 
 | 93 |     const Collection<Key> collection = getCollection<Key>(); | 
 | 94 |     return collection.get(key); | 
 | 95 | } | 
 | 96 |  | 
 | 97 | template <typename Key> | 
 | 98 | status_t Engine::add(const std::string &name, const Key &key) | 
 | 99 | { | 
 | 100 |     Collection<Key> &collection = getCollection<Key>(); | 
 | 101 |     return collection.add(name, key); | 
 | 102 | } | 
 | 103 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 104 | template <typename Property, typename Key> | 
 | 105 | Property Engine::getPropertyForKey(Key key) const | 
 | 106 | { | 
 | 107 |     Element<Key> *element = getFromCollection<Key>(key); | 
 | 108 |     if (element == NULL) { | 
 | 109 |         ALOGE("%s: Element not found within collection", __FUNCTION__); | 
 | 110 |         return static_cast<Property>(0); | 
 | 111 |     } | 
 | 112 |     return element->template get<Property>(); | 
 | 113 | } | 
 | 114 |  | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 115 | bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream, | 
 | 116 |                                        const audio_stream_type_t &profile) | 
| François Gaffie | d1ab2bd | 2015-12-02 18:20:06 +0100 | [diff] [blame] | 117 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 118 |     if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) { | 
| Eric Laurent | f5aa58d | 2019-02-22 18:20:11 -0800 | [diff] [blame] | 119 |         switchVolumeCurve(profile, stream); | 
| François Gaffie | d1ab2bd | 2015-12-02 18:20:06 +0100 | [diff] [blame] | 120 |         return true; | 
 | 121 |     } | 
 | 122 |     return false; | 
 | 123 | } | 
 | 124 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 125 | template <typename Property, typename Key> | 
 | 126 | bool Engine::setPropertyForKey(const Property &property, const Key &key) | 
 | 127 | { | 
 | 128 |     Element<Key> *element = getFromCollection<Key>(key); | 
 | 129 |     if (element == NULL) { | 
 | 130 |         ALOGE("%s: Element not found within collection", __FUNCTION__); | 
 | 131 |         return BAD_VALUE; | 
 | 132 |     } | 
 | 133 |     return element->template set<Property>(property) == NO_ERROR; | 
 | 134 | } | 
 | 135 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 136 | status_t Engine::setPhoneState(audio_mode_t mode) | 
 | 137 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 138 |     status_t status = mPolicyParameterMgr->setPhoneState(mode); | 
 | 139 |     if (status != NO_ERROR) { | 
 | 140 |         return status; | 
 | 141 |     } | 
 | 142 |     return EngineBase::setPhoneState(mode); | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 143 | } | 
 | 144 |  | 
 | 145 | audio_mode_t Engine::getPhoneState() const | 
 | 146 | { | 
 | 147 |     return mPolicyParameterMgr->getPhoneState(); | 
 | 148 | } | 
 | 149 |  | 
 | 150 | status_t Engine::setForceUse(audio_policy_force_use_t usage, | 
 | 151 |                                       audio_policy_forced_cfg_t config) | 
 | 152 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 153 |     status_t status = mPolicyParameterMgr->setForceUse(usage, config); | 
 | 154 |     if (status != NO_ERROR) { | 
 | 155 |         return status; | 
 | 156 |     } | 
 | 157 |     return EngineBase::setForceUse(usage, config); | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 158 | } | 
 | 159 |  | 
 | 160 | audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const | 
 | 161 | { | 
 | 162 |     return mPolicyParameterMgr->getForceUse(usage); | 
 | 163 | } | 
 | 164 |  | 
| François Gaffie | a3e696d | 2015-12-18 09:38:43 +0100 | [diff] [blame] | 165 | status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc, | 
| François Gaffie | 3305c11 | 2018-02-22 10:56:49 +0100 | [diff] [blame] | 166 |                                           audio_policy_dev_state_t state) | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 167 | { | 
| François Gaffie | 3305c11 | 2018-02-22 10:56:49 +0100 | [diff] [blame] | 168 |     mPolicyParameterMgr->setDeviceConnectionState(devDesc, state); | 
 | 169 |  | 
| François Gaffie | a3e696d | 2015-12-18 09:38:43 +0100 | [diff] [blame] | 170 |     if (audio_is_output_device(devDesc->type())) { | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 171 |         // FIXME: Use DeviceTypeSet when the interface is ready | 
| François Gaffie | a3e696d | 2015-12-18 09:38:43 +0100 | [diff] [blame] | 172 |         return mPolicyParameterMgr->setAvailableOutputDevices( | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 173 |                     deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types())); | 
| François Gaffie | a3e696d | 2015-12-18 09:38:43 +0100 | [diff] [blame] | 174 |     } else if (audio_is_input_device(devDesc->type())) { | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 175 |         // FIXME: Use DeviceTypeSet when the interface is ready | 
| François Gaffie | a3e696d | 2015-12-18 09:38:43 +0100 | [diff] [blame] | 176 |         return mPolicyParameterMgr->setAvailableInputDevices( | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 177 |                     deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types())); | 
| François Gaffie | a3e696d | 2015-12-18 09:38:43 +0100 | [diff] [blame] | 178 |     } | 
| Baekgyeong Kim | 0845152 | 2019-11-01 20:40:02 +0900 | [diff] [blame^] | 179 |     return EngineBase::setDeviceConnectionState(devDesc, state); | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 180 | } | 
 | 181 |  | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 182 | status_t Engine::loadAudioPolicyEngineConfig() | 
 | 183 | { | 
 | 184 |     auto result = EngineBase::loadAudioPolicyEngineConfig(); | 
 | 185 |  | 
| François Gaffie | 7188f1a | 2018-11-02 14:35:42 +0100 | [diff] [blame] | 186 |     // Custom XML Parsing | 
 | 187 |     auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) { | 
 | 188 |         for (auto& criterion : configCriteria) { | 
 | 189 |             engineConfig::CriterionType criterionType; | 
 | 190 |             for (auto &configCriterionType : configCriterionTypes) { | 
 | 191 |                 if (configCriterionType.name == criterion.typeName) { | 
 | 192 |                     criterionType = configCriterionType; | 
 | 193 |                     break; | 
 | 194 |                 } | 
 | 195 |             } | 
 | 196 |             ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s", | 
 | 197 |                         criterion.name.c_str()); | 
 | 198 |             mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive, | 
 | 199 |                                               criterionType.valuePairs, | 
 | 200 |                                               criterion.defaultLiteralValue); | 
 | 201 |         } | 
 | 202 |     }; | 
 | 203 |  | 
 | 204 |     loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 205 |     return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE; | 
 | 206 | } | 
 | 207 |  | 
 | 208 | DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const | 
 | 209 | { | 
 | 210 |     const auto productStrategies = getProductStrategies(); | 
 | 211 |     if (productStrategies.find(ps) == productStrategies.end()) { | 
 | 212 |         ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps); | 
 | 213 |         return {}; | 
 | 214 |     } | 
| Eric Laurent | af37777 | 2019-03-29 14:50:21 -0700 | [diff] [blame] | 215 |     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 216 |     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 217 |     DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types(); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 218 |  | 
 | 219 |     /** This is the only case handled programmatically because the PFW is unable to know the | 
 | 220 |      * activity of streams. | 
 | 221 |      * | 
 | 222 |      * -While media is playing on a remote device, use the the sonification behavior. | 
 | 223 |      * Note that we test this usecase before testing if media is playing because | 
 | 224 |      * the isStreamActive() method only informs about the activity of a stream, not | 
 | 225 |      * if it's for local playback. Note also that we use the same delay between both tests | 
 | 226 |      * | 
 | 227 |      * -When media is not playing anymore, fall back on the sonification behavior | 
 | 228 |      */ | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 229 |     DeviceTypeSet deviceTypes; | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 230 |     if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) && | 
 | 231 |             !is_state_in_call(getPhoneState()) && | 
| Eric Laurent | 83d17c2 | 2019-04-02 17:10:01 -0700 | [diff] [blame] | 232 |             !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC), | 
| François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 233 |                                       SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) && | 
| Eric Laurent | 83d17c2 | 2019-04-02 17:10:01 -0700 | [diff] [blame] | 234 |             outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC), | 
| François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 235 |                              SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 236 |         product_strategy_t strategyForMedia = | 
 | 237 |                 getProductStrategyForStream(AUDIO_STREAM_MUSIC); | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 238 |         deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 239 |     } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) && | 
| Eric Laurent | 83d17c2 | 2019-04-02 17:10:01 -0700 | [diff] [blame] | 240 |         (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) || | 
 | 241 |          outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 242 |             // do not route accessibility prompts to a digital output currently configured with a | 
 | 243 |             // compressed format as they would likely not be mixed and dropped. | 
 | 244 |             // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable. | 
 | 245 |         product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING); | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 246 |         deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 247 |     } else { | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 248 |         deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 249 |     } | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 250 |     if (deviceTypes.empty() || | 
 | 251 |             Intersection(deviceTypes, availableOutputDevicesTypes).empty()) { | 
| François Gaffie | c60c369 | 2019-08-09 15:41:24 +0200 | [diff] [blame] | 252 |         auto defaultDevice = getApmObserver()->getDefaultOutputDevice(); | 
 | 253 |         ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined"); | 
 | 254 |         return DeviceVector(defaultDevice); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 255 |     } | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 256 |     if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType( | 
 | 257 |             deviceTypes, AUDIO_DEVICE_OUT_BUS)) { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 258 |         // We do expect only one device for these types of devices | 
 | 259 |         // Criterion device address garantee this one is available | 
 | 260 |         // If this criterion is not wished, need to ensure this device is available | 
 | 261 |         const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str()); | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 262 |         ALOGV("%s:device %s %s %d", | 
 | 263 |                 __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps); | 
 | 264 |         auto busDevice = availableOutputDevices.getDevice( | 
 | 265 |                 *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT); | 
| François Gaffie | c60c369 | 2019-08-09 15:41:24 +0200 | [diff] [blame] | 266 |         if (busDevice == nullptr) { | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 267 |             ALOGE("%s:unavailable device %s %s, fallback on default", __func__, | 
 | 268 |                   dumpDeviceTypes(deviceTypes).c_str(), address.c_str()); | 
| François Gaffie | c60c369 | 2019-08-09 15:41:24 +0200 | [diff] [blame] | 269 |             auto defaultDevice = getApmObserver()->getDefaultOutputDevice(); | 
 | 270 |             ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available"); | 
 | 271 |             return DeviceVector(defaultDevice); | 
 | 272 |         } | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 273 |         return DeviceVector(busDevice); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 274 |     } | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 275 |     ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps); | 
 | 276 |     return availableOutputDevices.getDevicesFromTypes(deviceTypes); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 277 | } | 
 | 278 |  | 
 | 279 | DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes, | 
 | 280 |                                                    const sp<DeviceDescriptor> &preferredDevice, | 
 | 281 |                                                    bool fromCache) const | 
 | 282 | { | 
 | 283 |     // First check for explict routing device | 
 | 284 |     if (preferredDevice != nullptr) { | 
 | 285 |         ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str()); | 
 | 286 |         return DeviceVector(preferredDevice); | 
 | 287 |     } | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 288 |     product_strategy_t strategy = getProductStrategyForAttributes(attributes); | 
| Eric Laurent | af37777 | 2019-03-29 14:50:21 -0700 | [diff] [blame] | 289 |     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 290 |     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 291 |     // | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 292 |     // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to | 
 | 293 |     // be by APM? | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 294 |     // | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 295 |     // Honor explicit routing requests only if all active clients have a preferred route in which | 
 | 296 |     // case the last active client route is used | 
 | 297 |     sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices); | 
 | 298 |     if (device != nullptr) { | 
 | 299 |         return DeviceVector(device); | 
 | 300 |     } | 
 | 301 |  | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 302 |     return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy); | 
 | 303 | } | 
 | 304 |  | 
 | 305 | DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const | 
 | 306 | { | 
 | 307 |     auto attributes = EngineBase::getAttributesForStreamType(stream); | 
 | 308 |     return getOutputDevicesForAttributes(attributes, nullptr, fromCache); | 
 | 309 | } | 
 | 310 |  | 
 | 311 | sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr, | 
| Mikhail Naganov | bfac583 | 2019-03-05 16:55:28 -0800 | [diff] [blame] | 312 |                                                          sp<AudioPolicyMix> *mix) const | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 313 | { | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 314 |     const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection(); | 
| Eric Laurent | af37777 | 2019-03-29 14:50:21 -0700 | [diff] [blame] | 315 |     const auto availableInputDevices = getApmObserver()->getAvailableInputDevices(); | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 316 |     const auto &inputs = getApmObserver()->getInputs(); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 317 |     std::string address; | 
 | 318 |     // | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 319 |     // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered | 
 | 320 |     // first as it used to be by APM? | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 321 |     // | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 322 |     // Honor explicit routing requests only if all active clients have a preferred route in which | 
 | 323 |     // case the last active client route is used | 
 | 324 |     sp<DeviceDescriptor> device = | 
 | 325 |             findPreferredDevice(inputs, attr.source, availableInputDevices); | 
 | 326 |     if (device != nullptr) { | 
 | 327 |         return device; | 
 | 328 |     } | 
 | 329 |  | 
 | 330 |     device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix); | 
 | 331 |     if (device != nullptr) { | 
 | 332 |         return device; | 
 | 333 |     } | 
 | 334 |  | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 335 |     audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source); | 
 | 336 |  | 
 | 337 |     if (audio_is_remote_submix_device(deviceType)) { | 
 | 338 |         address = "0"; | 
 | 339 |         std::size_t pos; | 
 | 340 |         std::string tags { attr.tags }; | 
 | 341 |         if ((pos = tags.find("addr=")) != std::string::npos) { | 
 | 342 |             address = tags.substr(pos + std::strlen("addr=")); | 
 | 343 |         } | 
 | 344 |     } | 
| François Gaffie | c005e56 | 2018-11-06 15:04:49 +0100 | [diff] [blame] | 345 |     return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT); | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 346 | } | 
 | 347 |  | 
 | 348 | void Engine::updateDeviceSelectionCache() | 
 | 349 | { | 
 | 350 |     for (const auto &iter : getProductStrategies()) { | 
 | 351 |         const auto &strategy = iter.second; | 
 | 352 |         mDevicesForStrategies[strategy->getId()] = getDevicesForProductStrategy(strategy->getId()); | 
 | 353 |     } | 
 | 354 | } | 
 | 355 |  | 
| François Gaffie | f1e9508 | 2018-11-02 13:53:31 +0100 | [diff] [blame] | 356 | void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy, | 
 | 357 |                                                 const std::string &address) | 
 | 358 | { | 
 | 359 |     if (getProductStrategies().find(strategy) == getProductStrategies().end()) { | 
 | 360 |         ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(), | 
 | 361 |               strategy); | 
 | 362 |         return; | 
 | 363 |     } | 
 | 364 |     getProductStrategies().at(strategy)->setDeviceAddress(address); | 
 | 365 | } | 
 | 366 |  | 
 | 367 | bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio_devices_t devices) | 
 | 368 | { | 
 | 369 |     if (getProductStrategies().find(strategy) == getProductStrategies().end()) { | 
 | 370 |         ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy); | 
 | 371 |         return false; | 
 | 372 |     } | 
| jiabin | 12dc6b0 | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 373 |     // FIXME: stop using deviceTypesFromBitMask when the interface is ready | 
 | 374 |     getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices)); | 
| François Gaffie | f1e9508 | 2018-11-02 13:53:31 +0100 | [diff] [blame] | 375 |     return true; | 
 | 376 | } | 
 | 377 |  | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 378 | template <> | 
| Mikhail Naganov | e13c679 | 2019-05-14 10:32:51 -0700 | [diff] [blame] | 379 | EngineInterface *Engine::queryInterface() | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 380 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 381 |     return this; | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 382 | } | 
 | 383 |  | 
 | 384 | template <> | 
 | 385 | AudioPolicyPluginInterface *Engine::queryInterface() | 
 | 386 | { | 
| François Gaffie | dc7553f | 2018-11-02 10:39:57 +0100 | [diff] [blame] | 387 |     return this; | 
| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame] | 388 | } | 
 | 389 |  | 
 | 390 | } // namespace audio_policy | 
 | 391 | } // namespace android | 
 | 392 |  | 
 | 393 |  |