blob: dad663e05165921cf83c171e6cfdb9f24150a762 [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{
Mikhail Naganovf1b6d972023-05-02 13:56:01 -070071}
72
73status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
74{
75 status_t loadResult = loadAudioPolicyEngineConfig(xmlFilePath);
François Gaffiedc7553f2018-11-02 10:39:57 +010076 if (loadResult < 0) {
77 ALOGE("Policy Engine configuration is invalid.");
78 }
Mikhail Naganovf1b6d972023-05-02 13:56:01 -070079 return loadResult;
François Gaffie20f06f92015-03-24 09:01:14 +010080}
81
François Gaffie20f06f92015-03-24 09:01:14 +010082status_t Engine::initCheck()
83{
François Gaffieab1837a2019-10-15 10:48:50 +020084 std::string error;
85 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
86 ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
François Gaffie0f17ab72015-05-13 18:13:00 +020087 return NO_INIT;
88 }
François Gaffiedc7553f2018-11-02 10:39:57 +010089 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +010090}
91
François Gaffie20f06f92015-03-24 09:01:14 +010092template <typename Key>
93Element<Key> *Engine::getFromCollection(const Key &key) const
94{
95 const Collection<Key> collection = getCollection<Key>();
96 return collection.get(key);
97}
98
99template <typename Key>
100status_t Engine::add(const std::string &name, const Key &key)
101{
102 Collection<Key> &collection = getCollection<Key>();
103 return collection.add(name, key);
104}
105
François Gaffie20f06f92015-03-24 09:01:14 +0100106template <typename Property, typename Key>
107Property Engine::getPropertyForKey(Key key) const
108{
109 Element<Key> *element = getFromCollection<Key>(key);
110 if (element == NULL) {
111 ALOGE("%s: Element not found within collection", __FUNCTION__);
112 return static_cast<Property>(0);
113 }
114 return element->template get<Property>();
115}
116
François Gaffiedc7553f2018-11-02 10:39:57 +0100117bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
118 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100119{
François Gaffiedc7553f2018-11-02 10:39:57 +0100120 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
Eric Laurentf5aa58d2019-02-22 18:20:11 -0800121 switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100122 return true;
123 }
124 return false;
125}
126
François Gaffie20f06f92015-03-24 09:01:14 +0100127template <typename Property, typename Key>
128bool Engine::setPropertyForKey(const Property &property, const Key &key)
129{
130 Element<Key> *element = getFromCollection<Key>(key);
131 if (element == NULL) {
132 ALOGE("%s: Element not found within collection", __FUNCTION__);
Francois Gaffie15811d32020-01-14 17:26:02 +0100133 return false;
François Gaffie20f06f92015-03-24 09:01:14 +0100134 }
135 return element->template set<Property>(property) == NO_ERROR;
136}
137
François Gaffie20f06f92015-03-24 09:01:14 +0100138status_t Engine::setPhoneState(audio_mode_t mode)
139{
François Gaffiedc7553f2018-11-02 10:39:57 +0100140 status_t status = mPolicyParameterMgr->setPhoneState(mode);
141 if (status != NO_ERROR) {
142 return status;
143 }
144 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100145}
146
147audio_mode_t Engine::getPhoneState() const
148{
149 return mPolicyParameterMgr->getPhoneState();
150}
151
152status_t Engine::setForceUse(audio_policy_force_use_t usage,
153 audio_policy_forced_cfg_t config)
154{
François Gaffiedc7553f2018-11-02 10:39:57 +0100155 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
156 if (status != NO_ERROR) {
157 return status;
158 }
159 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100160}
161
162audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
163{
164 return mPolicyParameterMgr->getForceUse(usage);
165}
166
Eric Laurent32d01f32022-12-22 16:16:21 +0100167status_t Engine::setOutputDevicesConnectionState(const DeviceVector &devices,
168 audio_policy_dev_state_t state)
169{
170 for (const auto &device : devices) {
171 mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
172 }
173 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
174 if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
175 availableOutputDevices.remove(devices);
176 } else {
177 availableOutputDevices.add(devices);
178 }
179 return mPolicyParameterMgr->setAvailableOutputDevices(availableOutputDevices.types());
180}
181
François Gaffieab1837a2019-10-15 10:48:50 +0200182status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
François Gaffie3305c112018-02-22 10:56:49 +0100183 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100184{
Francois Gaffiea12de212021-10-22 10:54:33 +0200185 mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
François Gaffieab1837a2019-10-15 10:48:50 +0200186 if (audio_is_output_device(device->type())) {
François Gaffiea3e696d2015-12-18 09:38:43 +0100187 return mPolicyParameterMgr->setAvailableOutputDevices(
Francois Gaffiea12de212021-10-22 10:54:33 +0200188 getApmObserver()->getAvailableOutputDevices().types());
François Gaffieab1837a2019-10-15 10:48:50 +0200189 } else if (audio_is_input_device(device->type())) {
François Gaffiea3e696d2015-12-18 09:38:43 +0100190 return mPolicyParameterMgr->setAvailableInputDevices(
Francois Gaffiea12de212021-10-22 10:54:33 +0200191 getApmObserver()->getAvailableInputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100192 }
François Gaffieab1837a2019-10-15 10:48:50 +0200193 return EngineBase::setDeviceConnectionState(device, state);
François Gaffie20f06f92015-03-24 09:01:14 +0100194}
195
Mikhail Naganovf1b6d972023-05-02 13:56:01 -0700196status_t Engine::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
François Gaffiedc7553f2018-11-02 10:39:57 +0100197{
Mikhail Naganovf1b6d972023-05-02 13:56:01 -0700198 auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath);
François Gaffiedc7553f2018-11-02 10:39:57 +0100199
François Gaffie7188f1a2018-11-02 14:35:42 +0100200 // Custom XML Parsing
201 auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
202 for (auto& criterion : configCriteria) {
203 engineConfig::CriterionType criterionType;
204 for (auto &configCriterionType : configCriterionTypes) {
205 if (configCriterionType.name == criterion.typeName) {
206 criterionType = configCriterionType;
207 break;
208 }
209 }
210 ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
211 criterion.name.c_str());
212 mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
213 criterionType.valuePairs,
214 criterion.defaultLiteralValue);
215 }
216 };
217
218 loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100219 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
220}
221
Eric Laurent32d01f32022-12-22 16:16:21 +0100222status_t Engine::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
223 const AudioDeviceTypeAddrVector &devices)
224{
225 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
226 DeviceVector prevDisabledDevices =
227 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
228 status_t status = EngineBase::setDevicesRoleForStrategy(strategy, role, devices);
229 if (status != NO_ERROR) {
230 return status;
231 }
232 DeviceVector newDisabledDevices =
233 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
234 if (role == DEVICE_ROLE_PREFERRED) {
235 DeviceVector reenabledDevices = prevDisabledDevices;
236 reenabledDevices.remove(newDisabledDevices);
237 if (reenabledDevices.empty()) {
238 ALOGD("%s DEVICE_ROLE_PREFERRED empty renabled devices", __func__);
239 return status;
240 }
241 // some devices were moved from disabled to preferred, need to force a resync for these
242 enableDevicesForStrategy(strategy, prevDisabledDevices);
243 }
244 if (newDisabledDevices.empty()) {
245 return status;
246 }
247 return disableDevicesForStrategy(strategy, newDisabledDevices);
248}
249
250status_t Engine::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
251 const AudioDeviceTypeAddrVector &devices)
252{
253 const auto productStrategies = getProductStrategies();
254 if (productStrategies.find(strategy) == end(productStrategies)) {
255 ALOGE("%s invalid %d", __func__, strategy);
256 return BAD_VALUE;
257 }
258 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
259 DeviceVector prevDisabledDevices =
260 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
261 status_t status = EngineBase::removeDevicesRoleForStrategy(strategy, role, devices);
262 if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED) {
263 return status;
264 }
265 // Removing ROLE_DISABLED for given devices, need to force a resync for these
266 enableDevicesForStrategy(strategy, prevDisabledDevices);
267
268 DeviceVector remainingDisabledDevices = getDisabledDevicesForProductStrategy(
269 availableOutputDevices, strategy);
270 if (remainingDisabledDevices.empty()) {
271 return status;
272 }
273 return disableDevicesForStrategy(strategy, remainingDisabledDevices);
274}
275
276status_t Engine::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
277{
278 const auto productStrategies = getProductStrategies();
279 if (productStrategies.find(strategy) == end(productStrategies)) {
280 ALOGE("%s invalid %d", __func__, strategy);
281 return BAD_VALUE;
282 }
283 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
284 DeviceVector prevDisabledDevices =
285 getDisabledDevicesForProductStrategy(availableOutputDevices, strategy);
286 status_t status = EngineBase::clearDevicesRoleForStrategy(strategy, role);
287 if (status != NO_ERROR || role == DEVICE_ROLE_PREFERRED || prevDisabledDevices.empty()) {
288 return status;
289 }
290 // Disabled devices were removed, need to force a resync for these
291 enableDevicesForStrategy(strategy, prevDisabledDevices);
292 return NO_ERROR;
293}
294
295void Engine::enableDevicesForStrategy(product_strategy_t strategy __unused,
296 const DeviceVector &devicesToEnable) {
297 // devices were (re)enabled, need to force a resync for these
298 setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
299 setOutputDevicesConnectionState(devicesToEnable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
300}
301
302status_t Engine::disableDevicesForStrategy(product_strategy_t strategy,
303 const DeviceVector &devicesToDisable) {
304 // Filter out disabled devices for this strategy.
305 // However, to update the output device decision, availability criterion shall be updated,
306 // which may impact other strategies. So, as a WA, reconsider now and later to prevent from
307 // altering decision for other strategies;
308 setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
309
310 DeviceTypeSet deviceTypes = getProductStrategies().getDeviceTypesForProductStrategy(strategy);
311 const std::string address(getProductStrategies().getDeviceAddressForProductStrategy(strategy));
312
313 setOutputDevicesConnectionState(devicesToDisable, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
314
315 // Force reapply devices for given strategy
316 getProductStrategies().at(strategy)->setDeviceTypes(deviceTypes);
317 setDeviceAddressForProductStrategy(strategy, address);
318 return NO_ERROR;
319}
320
François Gaffiedc7553f2018-11-02 10:39:57 +0100321DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
322{
Eric Laurent32d01f32022-12-22 16:16:21 +0100323 DeviceVector selectedDevices = {};
324 DeviceVector disabledDevices = {};
François Gaffiedc7553f2018-11-02 10:39:57 +0100325 const auto productStrategies = getProductStrategies();
326 if (productStrategies.find(ps) == productStrategies.end()) {
327 ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
Eric Laurent32d01f32022-12-22 16:16:21 +0100328 return selectedDevices;
François Gaffiedc7553f2018-11-02 10:39:57 +0100329 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100330 DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiedc7553f2018-11-02 10:39:57 +0100331 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
jiabin12dc6b02019-10-01 09:38:30 -0700332 DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
François Gaffiedc7553f2018-11-02 10:39:57 +0100333
Eric Laurent32d01f32022-12-22 16:16:21 +0100334 // check if this strategy has a preferred device that is available,
335 // if yes, give priority to it.
336 DeviceVector preferredAvailableDevVec =
337 getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, ps);
338 if (!preferredAvailableDevVec.isEmpty()) {
339 return preferredAvailableDevVec;
340 }
341
François Gaffiedc7553f2018-11-02 10:39:57 +0100342 /** This is the only case handled programmatically because the PFW is unable to know the
343 * activity of streams.
344 *
345 * -While media is playing on a remote device, use the the sonification behavior.
346 * Note that we test this usecase before testing if media is playing because
347 * the isStreamActive() method only informs about the activity of a stream, not
348 * if it's for local playback. Note also that we use the same delay between both tests
349 *
350 * -When media is not playing anymore, fall back on the sonification behavior
351 */
jiabin12dc6b02019-10-01 09:38:30 -0700352 DeviceTypeSet deviceTypes;
Eric Laurent32d01f32022-12-22 16:16:21 +0100353 product_strategy_t psOrFallback = ps;
François Gaffiedc7553f2018-11-02 10:39:57 +0100354 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
355 !is_state_in_call(getPhoneState()) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700356 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100357 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700358 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100359 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
Eric Laurent32d01f32022-12-22 16:16:21 +0100360 psOrFallback = getProductStrategyForStream(AUDIO_STREAM_MUSIC);
François Gaffiedc7553f2018-11-02 10:39:57 +0100361 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700362 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
363 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100364 // do not route accessibility prompts to a digital output currently configured with a
365 // compressed format as they would likely not be mixed and dropped.
366 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
Eric Laurent32d01f32022-12-22 16:16:21 +0100367 psOrFallback = getProductStrategyForStream(AUDIO_STREAM_RING);
François Gaffiedc7553f2018-11-02 10:39:57 +0100368 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100369 disabledDevices = getDisabledDevicesForProductStrategy(availableOutputDevices, psOrFallback);
370 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(psOrFallback);
371 // In case a fallback is decided on other strategy, prevent from selecting this device if
372 // disabled for current strategy.
373 availableOutputDevices.remove(disabledDevices);
374
jiabin12dc6b02019-10-01 09:38:30 -0700375 if (deviceTypes.empty() ||
376 Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
François Gaffiec60c3692019-08-09 15:41:24 +0200377 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
378 ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
Eric Laurent32d01f32022-12-22 16:16:21 +0100379 selectedDevices = DeviceVector(defaultDevice);
380 } else if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
jiabin12dc6b02019-10-01 09:38:30 -0700381 deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100382 // We do expect only one device for these types of devices
383 // Criterion device address garantee this one is available
384 // If this criterion is not wished, need to ensure this device is available
385 const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
jiabin12dc6b02019-10-01 09:38:30 -0700386 ALOGV("%s:device %s %s %d",
387 __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
388 auto busDevice = availableOutputDevices.getDevice(
389 *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
François Gaffiec60c3692019-08-09 15:41:24 +0200390 if (busDevice == nullptr) {
jiabin12dc6b02019-10-01 09:38:30 -0700391 ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
392 dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
François Gaffiec60c3692019-08-09 15:41:24 +0200393 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
394 ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
Eric Laurent32d01f32022-12-22 16:16:21 +0100395 selectedDevices = DeviceVector(defaultDevice);
396 } else {
397 selectedDevices = DeviceVector(busDevice);
François Gaffiec60c3692019-08-09 15:41:24 +0200398 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100399 } else {
400 ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
401 selectedDevices = availableOutputDevices.getDevicesFromTypes(deviceTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100402 }
Eric Laurent32d01f32022-12-22 16:16:21 +0100403 return selectedDevices;
François Gaffiedc7553f2018-11-02 10:39:57 +0100404}
405
406DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
407 const sp<DeviceDescriptor> &preferredDevice,
408 bool fromCache) const
409{
410 // First check for explict routing device
411 if (preferredDevice != nullptr) {
412 ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
413 return DeviceVector(preferredDevice);
414 }
François Gaffiec005e562018-11-06 15:04:49 +0100415 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
Eric Laurentaf377772019-03-29 14:50:21 -0700416 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100417 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100418 //
François Gaffiec005e562018-11-06 15:04:49 +0100419 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
420 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100421 //
François Gaffiec005e562018-11-06 15:04:49 +0100422 // Honor explicit routing requests only if all active clients have a preferred route in which
423 // case the last active client route is used
424 sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
425 if (device != nullptr) {
426 return DeviceVector(device);
427 }
Francois Gaffie6f52ff92020-08-25 08:53:53 +0200428 return fromCache? getCachedDevices(strategy) : getDevicesForProductStrategy(strategy);
429}
François Gaffiec005e562018-11-06 15:04:49 +0100430
Francois Gaffie6f52ff92020-08-25 08:53:53 +0200431DeviceVector Engine::getCachedDevices(product_strategy_t ps) const
432{
433 return mDevicesForStrategies.find(ps) != mDevicesForStrategies.end() ?
434 mDevicesForStrategies.at(ps) : DeviceVector{};
François Gaffiedc7553f2018-11-02 10:39:57 +0100435}
436
437DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
438{
439 auto attributes = EngineBase::getAttributesForStreamType(stream);
440 return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
441}
442
443sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
yuanjiahsu0735bf32021-03-18 08:12:54 +0800444 uid_t uid,
Jan Sebechlebsky1a80c062022-08-09 15:21:18 +0200445 audio_session_t session,
Mikhail Naganovbfac5832019-03-05 16:55:28 -0800446 sp<AudioPolicyMix> *mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100447{
François Gaffiec005e562018-11-06 15:04:49 +0100448 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
Eric Laurentaf377772019-03-29 14:50:21 -0700449 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100450 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100451 std::string address;
452 //
François Gaffiec005e562018-11-06 15:04:49 +0100453 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
454 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100455 //
François Gaffiec005e562018-11-06 15:04:49 +0100456 // Honor explicit routing requests only if all active clients have a preferred route in which
457 // case the last active client route is used
458 sp<DeviceDescriptor> device =
459 findPreferredDevice(inputs, attr.source, availableInputDevices);
460 if (device != nullptr) {
461 return device;
462 }
463
Jan Sebechlebsky28ed9452022-09-15 17:57:42 +0200464 device = policyMixes.getDeviceAndMixForInputSource(attr,
yuanjiahsu0735bf32021-03-18 08:12:54 +0800465 availableInputDevices,
466 uid,
Jan Sebechlebsky1a80c062022-08-09 15:21:18 +0200467 session,
yuanjiahsu0735bf32021-03-18 08:12:54 +0800468 mix);
François Gaffiec005e562018-11-06 15:04:49 +0100469 if (device != nullptr) {
470 return device;
471 }
472
François Gaffiedc7553f2018-11-02 10:39:57 +0100473 audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
474
475 if (audio_is_remote_submix_device(deviceType)) {
476 address = "0";
477 std::size_t pos;
478 std::string tags { attr.tags };
479 if ((pos = tags.find("addr=")) != std::string::npos) {
480 address = tags.substr(pos + std::strlen("addr="));
481 }
482 }
François Gaffiec005e562018-11-06 15:04:49 +0100483 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100484}
485
François Gaffief1e95082018-11-02 13:53:31 +0100486void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
487 const std::string &address)
488{
489 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
490 ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
491 strategy);
492 return;
493 }
494 getProductStrategies().at(strategy)->setDeviceAddress(address);
495}
496
Francois Gaffiea12de212021-10-22 10:54:33 +0200497bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, uint64_t devices)
François Gaffief1e95082018-11-02 13:53:31 +0100498{
499 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
Francois Gaffiea12de212021-10-22 10:54:33 +0200500 ALOGE("%s: set device %" PRId64 " on invalid strategy %d", __FUNCTION__, devices, strategy);
François Gaffief1e95082018-11-02 13:53:31 +0100501 return false;
502 }
Francois Gaffiea12de212021-10-22 10:54:33 +0200503 // Here device matches the criterion value, need to rebuitd android device types;
504 DeviceTypeSet types =
505 mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(devices, true /*isOut*/);
506 getProductStrategies().at(strategy)->setDeviceTypes(types);
François Gaffief1e95082018-11-02 13:53:31 +0100507 return true;
508}
509
Francois Gaffiea12de212021-10-22 10:54:33 +0200510bool Engine::setDeviceForInputSource(const audio_source_t &inputSource, uint64_t device)
511{
512 DeviceTypeSet types = mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(
513 device, false /*isOut*/);
514 ALOG_ASSERT(types.size() <= 1, "one input device expected at most");
515 audio_devices_t deviceType = types.empty() ? AUDIO_DEVICE_IN_DEFAULT : *types.begin();
516 return setPropertyForKey<audio_devices_t, audio_source_t>(deviceType, inputSource);
517}
518
François Gaffie20f06f92015-03-24 09:01:14 +0100519template <>
Mikhail Naganove13c6792019-05-14 10:32:51 -0700520EngineInterface *Engine::queryInterface()
François Gaffie20f06f92015-03-24 09:01:14 +0100521{
François Gaffiedc7553f2018-11-02 10:39:57 +0100522 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100523}
524
525template <>
526AudioPolicyPluginInterface *Engine::queryInterface()
527{
François Gaffiedc7553f2018-11-02 10:39:57 +0100528 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100529}
530
531} // namespace audio_policy
532} // namespace android