blob: a7f92cdc782ff62818bd5cdb943defc61f1529d9 [file] [log] [blame]
François Gaffie20f06f92015-03-24 09:01:14 +01001/*
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 Gaffie20f06f92015-03-24 09:01:14 +010028#include "Stream.h"
29#include "InputSource.h"
François Gaffiedc7553f2018-11-02 10:39:57 +010030
31#include <EngineConfig.h>
François Gaffie20f06f92015-03-24 09:01:14 +010032#include <policy.h>
François Gaffiec005e562018-11-06 15:04:49 +010033#include <AudioIODescriptorInterface.h>
François Gaffie20f06f92015-03-24 09:01:14 +010034#include <ParameterManagerWrapper.h>
jiabin12dc6b02019-10-01 09:38:30 -070035#include <media/AudioContainers.h>
François Gaffie20f06f92015-03-24 09:01:14 +010036
François Gaffiec60c3692019-08-09 15:41:24 +020037#include <media/TypeConverter.h>
38
Francois Gaffiea12de212021-10-22 10:54:33 +020039#include <cinttypes>
40
François Gaffie20f06f92015-03-24 09:01:14 +010041using std::string;
42using std::map;
43
François Gaffief19cf792018-05-30 17:22:17 +020044namespace android {
45namespace audio_policy {
46
François Gaffie20f06f92015-03-24 09:01:14 +010047template <>
François Gaffie20f06f92015-03-24 09:01:14 +010048StreamCollection &Engine::getCollection<audio_stream_type_t>()
49{
50 return mStreamCollection;
51}
52template <>
François Gaffie20f06f92015-03-24 09:01:14 +010053InputSourceCollection &Engine::getCollection<audio_source_t>()
54{
55 return mInputSourceCollection;
56}
57
58template <>
François Gaffie20f06f92015-03-24 09:01:14 +010059const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
60{
61 return mStreamCollection;
62}
63template <>
François Gaffie20f06f92015-03-24 09:01:14 +010064const InputSourceCollection &Engine::getCollection<audio_source_t>() const
65{
66 return mInputSourceCollection;
67}
68
François Gaffiedc7553f2018-11-02 10:39:57 +010069Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
François Gaffie20f06f92015-03-24 09:01:14 +010070{
François Gaffiedc7553f2018-11-02 10:39:57 +010071 status_t loadResult = loadAudioPolicyEngineConfig();
72 if (loadResult < 0) {
73 ALOGE("Policy Engine configuration is invalid.");
74 }
François Gaffie20f06f92015-03-24 09:01:14 +010075}
76
77Engine::~Engine()
78{
François Gaffie20f06f92015-03-24 09:01:14 +010079 mStreamCollection.clear();
80 mInputSourceCollection.clear();
François Gaffie20f06f92015-03-24 09:01:14 +010081}
82
François Gaffie20f06f92015-03-24 09:01:14 +010083status_t Engine::initCheck()
84{
François Gaffieab1837a2019-10-15 10:48:50 +020085 std::string error;
86 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
87 ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
François Gaffie0f17ab72015-05-13 18:13:00 +020088 return NO_INIT;
89 }
François Gaffiedc7553f2018-11-02 10:39:57 +010090 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +010091}
92
François Gaffie20f06f92015-03-24 09:01:14 +010093template <typename Key>
94Element<Key> *Engine::getFromCollection(const Key &key) const
95{
96 const Collection<Key> collection = getCollection<Key>();
97 return collection.get(key);
98}
99
100template <typename Key>
101status_t Engine::add(const std::string &name, const Key &key)
102{
103 Collection<Key> &collection = getCollection<Key>();
104 return collection.add(name, key);
105}
106
François Gaffie20f06f92015-03-24 09:01:14 +0100107template <typename Property, typename Key>
108Property Engine::getPropertyForKey(Key key) const
109{
110 Element<Key> *element = getFromCollection<Key>(key);
111 if (element == NULL) {
112 ALOGE("%s: Element not found within collection", __FUNCTION__);
113 return static_cast<Property>(0);
114 }
115 return element->template get<Property>();
116}
117
François Gaffiedc7553f2018-11-02 10:39:57 +0100118bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
119 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100120{
François Gaffiedc7553f2018-11-02 10:39:57 +0100121 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
Eric Laurentf5aa58d2019-02-22 18:20:11 -0800122 switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100123 return true;
124 }
125 return false;
126}
127
François Gaffie20f06f92015-03-24 09:01:14 +0100128template <typename Property, typename Key>
129bool Engine::setPropertyForKey(const Property &property, const Key &key)
130{
131 Element<Key> *element = getFromCollection<Key>(key);
132 if (element == NULL) {
133 ALOGE("%s: Element not found within collection", __FUNCTION__);
Francois Gaffie15811d32020-01-14 17:26:02 +0100134 return false;
François Gaffie20f06f92015-03-24 09:01:14 +0100135 }
136 return element->template set<Property>(property) == NO_ERROR;
137}
138
François Gaffie20f06f92015-03-24 09:01:14 +0100139status_t Engine::setPhoneState(audio_mode_t mode)
140{
François Gaffiedc7553f2018-11-02 10:39:57 +0100141 status_t status = mPolicyParameterMgr->setPhoneState(mode);
142 if (status != NO_ERROR) {
143 return status;
144 }
145 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100146}
147
148audio_mode_t Engine::getPhoneState() const
149{
150 return mPolicyParameterMgr->getPhoneState();
151}
152
153status_t Engine::setForceUse(audio_policy_force_use_t usage,
154 audio_policy_forced_cfg_t config)
155{
François Gaffiedc7553f2018-11-02 10:39:57 +0100156 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
157 if (status != NO_ERROR) {
158 return status;
159 }
160 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100161}
162
163audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
164{
165 return mPolicyParameterMgr->getForceUse(usage);
166}
167
Eric Laurent32d01f32022-12-22 16:16:21 +0100168status_t Engine::setOutputDevicesConnectionState(const DeviceVector &devices,
169 audio_policy_dev_state_t state)
170{
171 for (const auto &device : devices) {
172 mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
173 }
174 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
175 if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
176 availableOutputDevices.remove(devices);
177 } else {
178 availableOutputDevices.add(devices);
179 }
180 return mPolicyParameterMgr->setAvailableOutputDevices(availableOutputDevices.types());
181}
182
François Gaffieab1837a2019-10-15 10:48:50 +0200183status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
François Gaffie3305c112018-02-22 10:56:49 +0100184 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100185{
Francois Gaffiea12de212021-10-22 10:54:33 +0200186 mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
François Gaffieab1837a2019-10-15 10:48:50 +0200187 if (audio_is_output_device(device->type())) {
François Gaffiea3e696d2015-12-18 09:38:43 +0100188 return mPolicyParameterMgr->setAvailableOutputDevices(
Francois Gaffiea12de212021-10-22 10:54:33 +0200189 getApmObserver()->getAvailableOutputDevices().types());
François Gaffieab1837a2019-10-15 10:48:50 +0200190 } else if (audio_is_input_device(device->type())) {
François Gaffiea3e696d2015-12-18 09:38:43 +0100191 return mPolicyParameterMgr->setAvailableInputDevices(
Francois Gaffiea12de212021-10-22 10:54:33 +0200192 getApmObserver()->getAvailableInputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100193 }
François Gaffieab1837a2019-10-15 10:48:50 +0200194 return EngineBase::setDeviceConnectionState(device, state);
François Gaffie20f06f92015-03-24 09:01:14 +0100195}
196
François Gaffiedc7553f2018-11-02 10:39:57 +0100197status_t Engine::loadAudioPolicyEngineConfig()
198{
199 auto result = EngineBase::loadAudioPolicyEngineConfig();
200
François Gaffie7188f1a2018-11-02 14:35:42 +0100201 // Custom XML Parsing
202 auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
203 for (auto& criterion : configCriteria) {
204 engineConfig::CriterionType criterionType;
205 for (auto &configCriterionType : configCriterionTypes) {
206 if (configCriterionType.name == criterion.typeName) {
207 criterionType = configCriterionType;
208 break;
209 }
210 }
211 ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
212 criterion.name.c_str());
213 mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
214 criterionType.valuePairs,
215 criterion.defaultLiteralValue);
216 }
217 };
218
219 loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100220 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
221}
222
Eric Laurent32d01f32022-12-22 16:16:21 +0100223status_t Engine::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
224 const AudioDeviceTypeAddrVector &devices)
225{
226 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
227 DeviceVector prevDisabledDevices =
228 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
229 status_t status = EngineBase::setDevicesRoleForStrategy(strategy, role, devices);
230 if (status != NO_ERROR) {
231 return status;
232 }
233 DeviceVector newDisabledDevices =
234 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
235 if (role == DEVICE_ROLE_PREFERRED) {
236 DeviceVector reenabledDevices = prevDisabledDevices;
237 reenabledDevices.remove(newDisabledDevices);
238 if (reenabledDevices.empty()) {
239 ALOGD("%s DEVICE_ROLE_PREFERRED empty renabled devices", __func__);
240 return status;
241 }
242 // some devices were moved from disabled to preferred, need to force a resync for these
243 enableDevicesForStrategy(strategy, prevDisabledDevices);
244 }
245 if (newDisabledDevices.empty()) {
246 return status;
247 }
248 return disableDevicesForStrategy(strategy, newDisabledDevices);
249}
250
251status_t Engine::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
252 const AudioDeviceTypeAddrVector &devices)
253{
254 const auto productStrategies = getProductStrategies();
255 if (productStrategies.find(strategy) == end(productStrategies)) {
256 ALOGE("%s invalid %d", __func__, strategy);
257 return BAD_VALUE;
258 }
259 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
260 DeviceVector prevDisabledDevices =
261 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
262 status_t status = EngineBase::removeDevicesRoleForStrategy(strategy, role, devices);
263 if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED) {
264 return status;
265 }
266 // Removing ROLE_DISABLED for given devices, need to force a resync for these
267 enableDevicesForStrategy(strategy, prevDisabledDevices);
268
269 DeviceVector remainingDisabledDevices = getDisabledDevicesForProductStrategy(
270 availableOutputDevices, strategy);
271 if (remainingDisabledDevices.empty()) {
272 return status;
273 }
274 return disableDevicesForStrategy(strategy, remainingDisabledDevices);
275}
276
277status_t Engine::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
278{
279 const auto productStrategies = getProductStrategies();
280 if (productStrategies.find(strategy) == end(productStrategies)) {
281 ALOGE("%s invalid %d", __func__, strategy);
282 return BAD_VALUE;
283 }
284 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
285 DeviceVector prevDisabledDevices =
286 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
287 status_t status = EngineBase::clearDevicesRoleForStrategy(strategy, role);
288 if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED || prevDisabledDevices.empty()) {
289 return status;
290 }
291 // Disabled devices were removed, need to force a resync for these
292 enableDevicesForStrategy(strategy, prevDisabledDevices);
293 return NO_ERROR;
294}
295
296void Engine::enableDevicesForStrategy(product_strategy_t strategy __unused,
297 const DeviceVector &devicesToEnable) {
298 // devices were (re)enabled, need to force a resync for these
299 setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
300 setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
301}
302
303status_t Engine::disableDevicesForStrategy(product_strategy_t strategy,
304 const DeviceVector &devicesToDisable) {
305 // Filter out disabled devices for this strategy.
306 // However, to update the output device decision, availability criterion shall be updated,
307 // which may impact other strategies. So, as a WA, reconsider now and later to prevent from
308 // altering decision for other strategies;
309 setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
310
311 DeviceTypeSet deviceTypes = getProductStrategies().getDeviceTypesForProductStrategy(strategy);
312 const std::string address(getProductStrategies().getDeviceAddressForProductStrategy(strategy));
313
314 setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
315
316 // Force reapply devices for given strategy
317 getProductStrategies().at(strategy)->setDeviceTypes(deviceTypes);
318 setDeviceAddressForProductStrategy(strategy, address);
319 return NO_ERROR;
320}
321
François Gaffiedc7553f2018-11-02 10:39:57 +0100322DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
323{
Eric Laurent32d01f32022-12-22 16:16:21 +0100324 DeviceVector selectedDevices = {};
325 DeviceVector disabledDevices = {};
François Gaffiedc7553f2018-11-02 10:39:57 +0100326 const auto productStrategies = getProductStrategies();
327 if (productStrategies.find(ps) == productStrategies.end()) {
328 ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
Eric Laurent32d01f32022-12-22 16:16:21 +0100329 return selectedDevices;
François Gaffiedc7553f2018-11-02 10:39:57 +0100330 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100331 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiedc7553f2018-11-02 10:39:57 +0100332 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
jiabin12dc6b02019-10-01 09:38:30 -0700333 DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
François Gaffiedc7553f2018-11-02 10:39:57 +0100334
Eric Laurent32d01f32022-12-22 16:16:21 +0100335 // check if this strategy has a preferred device that is available,
336 // if yes, give priority to it.
337 DeviceVector preferredAvailableDevVec =
338 getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps);
339 if (!preferredAvailableDevVec.isEmpty()) {
340 return preferredAvailableDevVec;
341 }
342
François Gaffiedc7553f2018-11-02 10:39:57 +0100343 /** This is the only case handled programmatically because the PFW is unable to know the
344 * activity of streams.
345 *
346 * -While media is playing on a remote device, use the the sonification behavior.
347 * Note that we test this usecase before testing if media is playing because
348 * the isStreamActive() method only informs about the activity of a stream, not
349 * if it's for local playback. Note also that we use the same delay between both tests
350 *
351 * -When media is not playing anymore, fall back on the sonification behavior
352 */
jiabin12dc6b02019-10-01 09:38:30 -0700353 DeviceTypeSet deviceTypes;
Eric Laurent32d01f32022-12-22 16:16:21 +0100354 product_strategy_t psOrFallback = ps;
François Gaffiedc7553f2018-11-02 10:39:57 +0100355 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
356 !is_state_in_call(getPhoneState()) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700357 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100358 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700359 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100360 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
Eric Laurent32d01f32022-12-22 16:16:21 +0100361 psOrFallback = getProductStrategyForStream(AUDIO_STREAM_MUSIC);
François Gaffiedc7553f2018-11-02 10:39:57 +0100362 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700363 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
364 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100365 // do not route accessibility prompts to a digital output currently configured with a
366 // compressed format as they would likely not be mixed and dropped.
367 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
Eric Laurent32d01f32022-12-22 16:16:21 +0100368 psOrFallback = getProductStrategyForStream(AUDIO_STREAM_RING);
François Gaffiedc7553f2018-11-02 10:39:57 +0100369 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100370 disabledDevices = getDisabledDevicesForProductStrategy(availableOutputDevices, psOrFallback);
371 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(psOrFallback);
372 // In case a fallback is decided on other strategy, prevent from selecting this device if
373 // disabled for current strategy.
374 availableOutputDevices.remove(disabledDevices);
375
jiabin12dc6b02019-10-01 09:38:30 -0700376 if (deviceTypes.empty() ||
377 Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
François Gaffiec60c3692019-08-09 15:41:24 +0200378 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
379 ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
Eric Laurent32d01f32022-12-22 16:16:21 +0100380 selectedDevices = DeviceVector(defaultDevice);
381 } else if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
jiabin12dc6b02019-10-01 09:38:30 -0700382 deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100383 // We do expect only one device for these types of devices
384 // Criterion device address garantee this one is available
385 // If this criterion is not wished, need to ensure this device is available
386 const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
jiabin12dc6b02019-10-01 09:38:30 -0700387 ALOGV("%s:device %s %s %d",
388 __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
389 auto busDevice = availableOutputDevices.getDevice(
390 *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
François Gaffiec60c3692019-08-09 15:41:24 +0200391 if (busDevice == nullptr) {
jiabin12dc6b02019-10-01 09:38:30 -0700392 ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
393 dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
François Gaffiec60c3692019-08-09 15:41:24 +0200394 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
395 ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
Eric Laurent32d01f32022-12-22 16:16:21 +0100396 selectedDevices = DeviceVector(defaultDevice);
397 } else {
398 selectedDevices = DeviceVector(busDevice);
François Gaffiec60c3692019-08-09 15:41:24 +0200399 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100400 } else {
401 ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
402 selectedDevices = availableOutputDevices.getDevicesFromTypes(deviceTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100403 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100404 return selectedDevices;
François Gaffiedc7553f2018-11-02 10:39:57 +0100405}
406
407DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
408 const sp<DeviceDescriptor> &preferredDevice,
409 bool fromCache) const
410{
411 // First check for explict routing device
412 if (preferredDevice != nullptr) {
413 ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
414 return DeviceVector(preferredDevice);
415 }
François Gaffiec005e562018-11-06 15:04:49 +0100416 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
Eric Laurentaf377772019-03-29 14:50:21 -0700417 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100418 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100419 //
François Gaffiec005e562018-11-06 15:04:49 +0100420 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
421 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100422 //
François Gaffiec005e562018-11-06 15:04:49 +0100423 // Honor explicit routing requests only if all active clients have a preferred route in which
424 // case the last active client route is used
425 sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
426 if (device != nullptr) {
427 return DeviceVector(device);
428 }
Francois Gaffie6f52ff92020-08-25 08:53:53 +0200429 return fromCache? getCachedDevices(strategy) : getDevicesForProductStrategy(strategy);
430}
François Gaffiec005e562018-11-06 15:04:49 +0100431
Francois Gaffie6f52ff92020-08-25 08:53:53 +0200432DeviceVector Engine::getCachedDevices(product_strategy_t ps) const
433{
434 return mDevicesForStrategies.find(ps) != mDevicesForStrategies.end() ?
435 mDevicesForStrategies.at(ps) : DeviceVector{};
François Gaffiedc7553f2018-11-02 10:39:57 +0100436}
437
438DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
439{
440 auto attributes = EngineBase::getAttributesForStreamType(stream);
441 return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
442}
443
444sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
yuanjiahsu0735bf32021-03-18 08:12:54 +0800445 uid_t uid,
Jan Sebechlebsky1a80c062022-08-09 15:21:18 +0200446 audio_session_t session,
Mikhail Naganovbfac5832019-03-05 16:55:28 -0800447 sp<AudioPolicyMix> *mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100448{
François Gaffiec005e562018-11-06 15:04:49 +0100449 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
Eric Laurentaf377772019-03-29 14:50:21 -0700450 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100451 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100452 std::string address;
453 //
François Gaffiec005e562018-11-06 15:04:49 +0100454 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
455 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100456 //
François Gaffiec005e562018-11-06 15:04:49 +0100457 // Honor explicit routing requests only if all active clients have a preferred route in which
458 // case the last active client route is used
459 sp<DeviceDescriptor> device =
460 findPreferredDevice(inputs, attr.source, availableInputDevices);
461 if (device != nullptr) {
462 return device;
463 }
464
Jan Sebechlebsky28ed9452022-09-15 17:57:42 +0200465 device = policyMixes.getDeviceAndMixForInputSource(attr,
yuanjiahsu0735bf32021-03-18 08:12:54 +0800466 availableInputDevices,
467 uid,
Jan Sebechlebsky1a80c062022-08-09 15:21:18 +0200468 session,
yuanjiahsu0735bf32021-03-18 08:12:54 +0800469 mix);
François Gaffiec005e562018-11-06 15:04:49 +0100470 if (device != nullptr) {
471 return device;
472 }
473
François Gaffiedc7553f2018-11-02 10:39:57 +0100474 audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
475
476 if (audio_is_remote_submix_device(deviceType)) {
477 address = "0";
478 std::size_t pos;
479 std::string tags { attr.tags };
480 if ((pos = tags.find("addr=")) != std::string::npos) {
481 address = tags.substr(pos + std::strlen("addr="));
482 }
483 }
François Gaffiec005e562018-11-06 15:04:49 +0100484 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100485}
486
François Gaffief1e95082018-11-02 13:53:31 +0100487void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
488 const std::string &address)
489{
490 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
491 ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
492 strategy);
493 return;
494 }
495 getProductStrategies().at(strategy)->setDeviceAddress(address);
496}
497
Francois Gaffiea12de212021-10-22 10:54:33 +0200498bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, uint64_t devices)
François Gaffief1e95082018-11-02 13:53:31 +0100499{
500 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
Francois Gaffiea12de212021-10-22 10:54:33 +0200501 ALOGE("%s: set device %" PRId64 " on invalid strategy %d", __FUNCTION__, devices, strategy);
François Gaffief1e95082018-11-02 13:53:31 +0100502 return false;
503 }
Francois Gaffiea12de212021-10-22 10:54:33 +0200504 // Here device matches the criterion value, need to rebuitd android device types;
505 DeviceTypeSet types =
506 mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(devices, true /*isOut*/);
507 getProductStrategies().at(strategy)->setDeviceTypes(types);
François Gaffief1e95082018-11-02 13:53:31 +0100508 return true;
509}
510
Francois Gaffiea12de212021-10-22 10:54:33 +0200511bool Engine::setDeviceForInputSource(const audio_source_t &inputSource, uint64_t device)
512{
513 DeviceTypeSet types = mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(
514 device, false /*isOut*/);
515 ALOG_ASSERT(types.size() <= 1, "one input device expected at most");
516 audio_devices_t deviceType = types.empty() ? AUDIO_DEVICE_IN_DEFAULT : *types.begin();
517 return setPropertyForKey<audio_devices_t, audio_source_t>(deviceType, inputSource);
518}
519
François Gaffie20f06f92015-03-24 09:01:14 +0100520template <>
Mikhail Naganove13c6792019-05-14 10:32:51 -0700521EngineInterface *Engine::queryInterface()
François Gaffie20f06f92015-03-24 09:01:14 +0100522{
François Gaffiedc7553f2018-11-02 10:39:57 +0100523 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100524}
525
526template <>
527AudioPolicyPluginInterface *Engine::queryInterface()
528{
François Gaffiedc7553f2018-11-02 10:39:57 +0100529 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100530}
531
532} // namespace audio_policy
533} // namespace android
534
535