blob: 39872940dbc855f00f9eda9557de989c17054c2a [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>
35
François Gaffiec60c3692019-08-09 15:41:24 +020036#include <media/TypeConverter.h>
37
François Gaffie20f06f92015-03-24 09:01:14 +010038using std::string;
39using std::map;
40
François Gaffief19cf792018-05-30 17:22:17 +020041namespace android {
42namespace audio_policy {
43
François Gaffie20f06f92015-03-24 09:01:14 +010044template <>
François Gaffie20f06f92015-03-24 09:01:14 +010045StreamCollection &Engine::getCollection<audio_stream_type_t>()
46{
47 return mStreamCollection;
48}
49template <>
François Gaffie20f06f92015-03-24 09:01:14 +010050InputSourceCollection &Engine::getCollection<audio_source_t>()
51{
52 return mInputSourceCollection;
53}
54
55template <>
François Gaffie20f06f92015-03-24 09:01:14 +010056const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
57{
58 return mStreamCollection;
59}
60template <>
François Gaffie20f06f92015-03-24 09:01:14 +010061const InputSourceCollection &Engine::getCollection<audio_source_t>() const
62{
63 return mInputSourceCollection;
64}
65
François Gaffiedc7553f2018-11-02 10:39:57 +010066Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
François Gaffie20f06f92015-03-24 09:01:14 +010067{
François Gaffiedc7553f2018-11-02 10:39:57 +010068 status_t loadResult = loadAudioPolicyEngineConfig();
69 if (loadResult < 0) {
70 ALOGE("Policy Engine configuration is invalid.");
71 }
François Gaffie20f06f92015-03-24 09:01:14 +010072}
73
74Engine::~Engine()
75{
François Gaffie20f06f92015-03-24 09:01:14 +010076 mStreamCollection.clear();
77 mInputSourceCollection.clear();
François Gaffie20f06f92015-03-24 09:01:14 +010078}
79
François Gaffie20f06f92015-03-24 09:01:14 +010080status_t Engine::initCheck()
81{
François Gaffiedc7553f2018-11-02 10:39:57 +010082 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
François Gaffie0f17ab72015-05-13 18:13:00 +020083 ALOGE("%s: could not start Policy PFW", __FUNCTION__);
François Gaffie0f17ab72015-05-13 18:13:00 +020084 return NO_INIT;
85 }
François Gaffiedc7553f2018-11-02 10:39:57 +010086 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +010087}
88
François Gaffie20f06f92015-03-24 09:01:14 +010089template <typename Key>
90Element<Key> *Engine::getFromCollection(const Key &key) const
91{
92 const Collection<Key> collection = getCollection<Key>();
93 return collection.get(key);
94}
95
96template <typename Key>
97status_t Engine::add(const std::string &name, const Key &key)
98{
99 Collection<Key> &collection = getCollection<Key>();
100 return collection.add(name, key);
101}
102
François Gaffie20f06f92015-03-24 09:01:14 +0100103template <typename Property, typename Key>
104Property Engine::getPropertyForKey(Key key) const
105{
106 Element<Key> *element = getFromCollection<Key>(key);
107 if (element == NULL) {
108 ALOGE("%s: Element not found within collection", __FUNCTION__);
109 return static_cast<Property>(0);
110 }
111 return element->template get<Property>();
112}
113
François Gaffiedc7553f2018-11-02 10:39:57 +0100114bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
115 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100116{
François Gaffiedc7553f2018-11-02 10:39:57 +0100117 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
Eric Laurentf5aa58d2019-02-22 18:20:11 -0800118 switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100119 return true;
120 }
121 return false;
122}
123
François Gaffie20f06f92015-03-24 09:01:14 +0100124template <typename Property, typename Key>
125bool Engine::setPropertyForKey(const Property &property, const Key &key)
126{
127 Element<Key> *element = getFromCollection<Key>(key);
128 if (element == NULL) {
129 ALOGE("%s: Element not found within collection", __FUNCTION__);
130 return BAD_VALUE;
131 }
132 return element->template set<Property>(property) == NO_ERROR;
133}
134
François Gaffie20f06f92015-03-24 09:01:14 +0100135status_t Engine::setPhoneState(audio_mode_t mode)
136{
François Gaffiedc7553f2018-11-02 10:39:57 +0100137 status_t status = mPolicyParameterMgr->setPhoneState(mode);
138 if (status != NO_ERROR) {
139 return status;
140 }
141 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100142}
143
144audio_mode_t Engine::getPhoneState() const
145{
146 return mPolicyParameterMgr->getPhoneState();
147}
148
149status_t Engine::setForceUse(audio_policy_force_use_t usage,
150 audio_policy_forced_cfg_t config)
151{
François Gaffiedc7553f2018-11-02 10:39:57 +0100152 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
153 if (status != NO_ERROR) {
154 return status;
155 }
156 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100157}
158
159audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
160{
161 return mPolicyParameterMgr->getForceUse(usage);
162}
163
François Gaffiea3e696d2015-12-18 09:38:43 +0100164status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
François Gaffie3305c112018-02-22 10:56:49 +0100165 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100166{
François Gaffie3305c112018-02-22 10:56:49 +0100167 mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
168
François Gaffiea3e696d2015-12-18 09:38:43 +0100169 if (audio_is_output_device(devDesc->type())) {
170 return mPolicyParameterMgr->setAvailableOutputDevices(
François Gaffiedc7553f2018-11-02 10:39:57 +0100171 getApmObserver()->getAvailableOutputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100172 } else if (audio_is_input_device(devDesc->type())) {
173 return mPolicyParameterMgr->setAvailableInputDevices(
François Gaffiedc7553f2018-11-02 10:39:57 +0100174 getApmObserver()->getAvailableInputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100175 }
176 return BAD_TYPE;
François Gaffie20f06f92015-03-24 09:01:14 +0100177}
178
François Gaffiedc7553f2018-11-02 10:39:57 +0100179status_t Engine::loadAudioPolicyEngineConfig()
180{
181 auto result = EngineBase::loadAudioPolicyEngineConfig();
182
François Gaffie7188f1a2018-11-02 14:35:42 +0100183 // Custom XML Parsing
184 auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
185 for (auto& criterion : configCriteria) {
186 engineConfig::CriterionType criterionType;
187 for (auto &configCriterionType : configCriterionTypes) {
188 if (configCriterionType.name == criterion.typeName) {
189 criterionType = configCriterionType;
190 break;
191 }
192 }
193 ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
194 criterion.name.c_str());
195 mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
196 criterionType.valuePairs,
197 criterion.defaultLiteralValue);
198 }
199 };
200
201 loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100202 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
203}
204
205DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
206{
207 const auto productStrategies = getProductStrategies();
208 if (productStrategies.find(ps) == productStrategies.end()) {
209 ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
210 return {};
211 }
Eric Laurentaf377772019-03-29 14:50:21 -0700212 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiedc7553f2018-11-02 10:39:57 +0100213 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
214 uint32_t availableOutputDevicesType = availableOutputDevices.types();
215
216 /** This is the only case handled programmatically because the PFW is unable to know the
217 * activity of streams.
218 *
219 * -While media is playing on a remote device, use the the sonification behavior.
220 * Note that we test this usecase before testing if media is playing because
221 * the isStreamActive() method only informs about the activity of a stream, not
222 * if it's for local playback. Note also that we use the same delay between both tests
223 *
224 * -When media is not playing anymore, fall back on the sonification behavior
225 */
226 audio_devices_t devices = AUDIO_DEVICE_NONE;
227 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
228 !is_state_in_call(getPhoneState()) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700229 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100230 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700231 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100232 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100233 product_strategy_t strategyForMedia =
234 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
235 devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
236 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700237 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
238 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100239 // do not route accessibility prompts to a digital output currently configured with a
240 // compressed format as they would likely not be mixed and dropped.
241 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
242 product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
243 devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
244 } else {
245 devices = productStrategies.getDeviceTypesForProductStrategy(ps);
246 }
247 if (devices == AUDIO_DEVICE_NONE ||
248 (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
François Gaffiec60c3692019-08-09 15:41:24 +0200249 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
250 ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
251 return DeviceVector(defaultDevice);
François Gaffiedc7553f2018-11-02 10:39:57 +0100252 }
253 if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
254 // We do expect only one device for these types of devices
255 // Criterion device address garantee this one is available
256 // If this criterion is not wished, need to ensure this device is available
257 const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
258 ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
François Gaffiec60c3692019-08-09 15:41:24 +0200259 auto busDevice = availableOutputDevices.getDevice(devices, address, AUDIO_FORMAT_DEFAULT);
260 if (busDevice == nullptr) {
261 ALOGE("%s:unavailable device 0x%x %s, fallback on default", __func__, devices,
262 address.c_str());
263 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
264 ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
265 return DeviceVector(defaultDevice);
266 }
François Gaffiedc7553f2018-11-02 10:39:57 +0100267 return DeviceVector(availableOutputDevices.getDevice(devices,
268 address,
269 AUDIO_FORMAT_DEFAULT));
270 }
271 ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
272 return availableOutputDevices.getDevicesFromTypeMask(devices);
273}
274
275DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
276 const sp<DeviceDescriptor> &preferredDevice,
277 bool fromCache) const
278{
279 // First check for explict routing device
280 if (preferredDevice != nullptr) {
281 ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
282 return DeviceVector(preferredDevice);
283 }
François Gaffiec005e562018-11-06 15:04:49 +0100284 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
Eric Laurentaf377772019-03-29 14:50:21 -0700285 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100286 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100287 //
François Gaffiec005e562018-11-06 15:04:49 +0100288 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
289 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100290 //
François Gaffiec005e562018-11-06 15:04:49 +0100291 // Honor explicit routing requests only if all active clients have a preferred route in which
292 // case the last active client route is used
293 sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
294 if (device != nullptr) {
295 return DeviceVector(device);
296 }
297
François Gaffiedc7553f2018-11-02 10:39:57 +0100298 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
299}
300
301DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
302{
303 auto attributes = EngineBase::getAttributesForStreamType(stream);
304 return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
305}
306
307sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
Mikhail Naganovbfac5832019-03-05 16:55:28 -0800308 sp<AudioPolicyMix> *mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100309{
François Gaffiec005e562018-11-06 15:04:49 +0100310 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
Eric Laurentaf377772019-03-29 14:50:21 -0700311 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100312 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100313 std::string address;
314 //
François Gaffiec005e562018-11-06 15:04:49 +0100315 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
316 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100317 //
François Gaffiec005e562018-11-06 15:04:49 +0100318 // Honor explicit routing requests only if all active clients have a preferred route in which
319 // case the last active client route is used
320 sp<DeviceDescriptor> device =
321 findPreferredDevice(inputs, attr.source, availableInputDevices);
322 if (device != nullptr) {
323 return device;
324 }
325
326 device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix);
327 if (device != nullptr) {
328 return device;
329 }
330
François Gaffiedc7553f2018-11-02 10:39:57 +0100331 audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
332
333 if (audio_is_remote_submix_device(deviceType)) {
334 address = "0";
335 std::size_t pos;
336 std::string tags { attr.tags };
337 if ((pos = tags.find("addr=")) != std::string::npos) {
338 address = tags.substr(pos + std::strlen("addr="));
339 }
340 }
François Gaffiec005e562018-11-06 15:04:49 +0100341 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100342}
343
344void Engine::updateDeviceSelectionCache()
345{
346 for (const auto &iter : getProductStrategies()) {
347 const auto &strategy = iter.second;
348 mDevicesForStrategies[strategy->getId()] = getDevicesForProductStrategy(strategy->getId());
349 }
350}
351
François Gaffief1e95082018-11-02 13:53:31 +0100352void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
353 const std::string &address)
354{
355 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
356 ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
357 strategy);
358 return;
359 }
360 getProductStrategies().at(strategy)->setDeviceAddress(address);
361}
362
363bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio_devices_t devices)
364{
365 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
366 ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
367 return false;
368 }
369 getProductStrategies().at(strategy)->setDeviceTypes(devices);
370 return true;
371}
372
François Gaffie20f06f92015-03-24 09:01:14 +0100373template <>
Mikhail Naganove13c6792019-05-14 10:32:51 -0700374EngineInterface *Engine::queryInterface()
François Gaffie20f06f92015-03-24 09:01:14 +0100375{
François Gaffiedc7553f2018-11-02 10:39:57 +0100376 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100377}
378
379template <>
380AudioPolicyPluginInterface *Engine::queryInterface()
381{
François Gaffiedc7553f2018-11-02 10:39:57 +0100382 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100383}
384
385} // namespace audio_policy
386} // namespace android
387
388