blob: 0a8868508b478b9b0b913c73d686909eed7a0baa [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
François Gaffie20f06f92015-03-24 09:01:14 +010039using std::string;
40using std::map;
41
François Gaffief19cf792018-05-30 17:22:17 +020042namespace android {
43namespace audio_policy {
44
François Gaffie20f06f92015-03-24 09:01:14 +010045template <>
François Gaffie20f06f92015-03-24 09:01:14 +010046StreamCollection &Engine::getCollection<audio_stream_type_t>()
47{
48 return mStreamCollection;
49}
50template <>
François Gaffie20f06f92015-03-24 09:01:14 +010051InputSourceCollection &Engine::getCollection<audio_source_t>()
52{
53 return mInputSourceCollection;
54}
55
56template <>
François Gaffie20f06f92015-03-24 09:01:14 +010057const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
58{
59 return mStreamCollection;
60}
61template <>
François Gaffie20f06f92015-03-24 09:01:14 +010062const InputSourceCollection &Engine::getCollection<audio_source_t>() const
63{
64 return mInputSourceCollection;
65}
66
François Gaffiedc7553f2018-11-02 10:39:57 +010067Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
François Gaffie20f06f92015-03-24 09:01:14 +010068{
François Gaffiedc7553f2018-11-02 10:39:57 +010069 status_t loadResult = loadAudioPolicyEngineConfig();
70 if (loadResult < 0) {
71 ALOGE("Policy Engine configuration is invalid.");
72 }
François Gaffie20f06f92015-03-24 09:01:14 +010073}
74
75Engine::~Engine()
76{
François Gaffie20f06f92015-03-24 09:01:14 +010077 mStreamCollection.clear();
78 mInputSourceCollection.clear();
François Gaffie20f06f92015-03-24 09:01:14 +010079}
80
François Gaffie20f06f92015-03-24 09:01:14 +010081status_t Engine::initCheck()
82{
François Gaffiedc7553f2018-11-02 10:39:57 +010083 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
François Gaffie0f17ab72015-05-13 18:13:00 +020084 ALOGE("%s: could not start Policy PFW", __FUNCTION__);
François Gaffie0f17ab72015-05-13 18:13:00 +020085 return NO_INIT;
86 }
François Gaffiedc7553f2018-11-02 10:39:57 +010087 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +010088}
89
François Gaffie20f06f92015-03-24 09:01:14 +010090template <typename Key>
91Element<Key> *Engine::getFromCollection(const Key &key) const
92{
93 const Collection<Key> collection = getCollection<Key>();
94 return collection.get(key);
95}
96
97template <typename Key>
98status_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 Gaffie20f06f92015-03-24 09:01:14 +0100104template <typename Property, typename Key>
105Property 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 Gaffiedc7553f2018-11-02 10:39:57 +0100115bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
116 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100117{
François Gaffiedc7553f2018-11-02 10:39:57 +0100118 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
Eric Laurentf5aa58d2019-02-22 18:20:11 -0800119 switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100120 return true;
121 }
122 return false;
123}
124
François Gaffie20f06f92015-03-24 09:01:14 +0100125template <typename Property, typename Key>
126bool 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 Gaffie20f06f92015-03-24 09:01:14 +0100136status_t Engine::setPhoneState(audio_mode_t mode)
137{
François Gaffiedc7553f2018-11-02 10:39:57 +0100138 status_t status = mPolicyParameterMgr->setPhoneState(mode);
139 if (status != NO_ERROR) {
140 return status;
141 }
142 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100143}
144
145audio_mode_t Engine::getPhoneState() const
146{
147 return mPolicyParameterMgr->getPhoneState();
148}
149
150status_t Engine::setForceUse(audio_policy_force_use_t usage,
151 audio_policy_forced_cfg_t config)
152{
François Gaffiedc7553f2018-11-02 10:39:57 +0100153 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
154 if (status != NO_ERROR) {
155 return status;
156 }
157 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100158}
159
160audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
161{
162 return mPolicyParameterMgr->getForceUse(usage);
163}
164
François Gaffiea3e696d2015-12-18 09:38:43 +0100165status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
François Gaffie3305c112018-02-22 10:56:49 +0100166 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100167{
François Gaffie3305c112018-02-22 10:56:49 +0100168 mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
169
François Gaffiea3e696d2015-12-18 09:38:43 +0100170 if (audio_is_output_device(devDesc->type())) {
jiabin12dc6b02019-10-01 09:38:30 -0700171 // FIXME: Use DeviceTypeSet when the interface is ready
François Gaffiea3e696d2015-12-18 09:38:43 +0100172 return mPolicyParameterMgr->setAvailableOutputDevices(
jiabin12dc6b02019-10-01 09:38:30 -0700173 deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
François Gaffiea3e696d2015-12-18 09:38:43 +0100174 } else if (audio_is_input_device(devDesc->type())) {
jiabin12dc6b02019-10-01 09:38:30 -0700175 // FIXME: Use DeviceTypeSet when the interface is ready
François Gaffiea3e696d2015-12-18 09:38:43 +0100176 return mPolicyParameterMgr->setAvailableInputDevices(
jiabin12dc6b02019-10-01 09:38:30 -0700177 deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
François Gaffiea3e696d2015-12-18 09:38:43 +0100178 }
179 return BAD_TYPE;
François Gaffie20f06f92015-03-24 09:01:14 +0100180}
181
François Gaffiedc7553f2018-11-02 10:39:57 +0100182status_t Engine::loadAudioPolicyEngineConfig()
183{
184 auto result = EngineBase::loadAudioPolicyEngineConfig();
185
François Gaffie7188f1a2018-11-02 14:35:42 +0100186 // 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 Gaffiedc7553f2018-11-02 10:39:57 +0100205 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
206}
207
208DeviceVector 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 Laurentaf377772019-03-29 14:50:21 -0700215 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiedc7553f2018-11-02 10:39:57 +0100216 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
jiabin12dc6b02019-10-01 09:38:30 -0700217 DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
François Gaffiedc7553f2018-11-02 10:39:57 +0100218
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 */
jiabin12dc6b02019-10-01 09:38:30 -0700229 DeviceTypeSet deviceTypes;
François Gaffiedc7553f2018-11-02 10:39:57 +0100230 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
231 !is_state_in_call(getPhoneState()) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700232 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100233 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700234 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100235 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100236 product_strategy_t strategyForMedia =
237 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
jiabin12dc6b02019-10-01 09:38:30 -0700238 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
François Gaffiedc7553f2018-11-02 10:39:57 +0100239 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700240 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
241 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100242 // 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);
jiabin12dc6b02019-10-01 09:38:30 -0700246 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
François Gaffiedc7553f2018-11-02 10:39:57 +0100247 } else {
jiabin12dc6b02019-10-01 09:38:30 -0700248 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
François Gaffiedc7553f2018-11-02 10:39:57 +0100249 }
jiabin12dc6b02019-10-01 09:38:30 -0700250 if (deviceTypes.empty() ||
251 Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
François Gaffiec60c3692019-08-09 15:41:24 +0200252 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
253 ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
254 return DeviceVector(defaultDevice);
François Gaffiedc7553f2018-11-02 10:39:57 +0100255 }
jiabin12dc6b02019-10-01 09:38:30 -0700256 if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
257 deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100258 // 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());
jiabin12dc6b02019-10-01 09:38:30 -0700262 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 Gaffiec60c3692019-08-09 15:41:24 +0200266 if (busDevice == nullptr) {
jiabin12dc6b02019-10-01 09:38:30 -0700267 ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
268 dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
François Gaffiec60c3692019-08-09 15:41:24 +0200269 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
270 ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
271 return DeviceVector(defaultDevice);
272 }
jiabin12dc6b02019-10-01 09:38:30 -0700273 return DeviceVector(busDevice);
François Gaffiedc7553f2018-11-02 10:39:57 +0100274 }
jiabin12dc6b02019-10-01 09:38:30 -0700275 ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
276 return availableOutputDevices.getDevicesFromTypes(deviceTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100277}
278
279DeviceVector 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 Gaffiec005e562018-11-06 15:04:49 +0100288 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
Eric Laurentaf377772019-03-29 14:50:21 -0700289 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100290 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100291 //
François Gaffiec005e562018-11-06 15:04:49 +0100292 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
293 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100294 //
François Gaffiec005e562018-11-06 15:04:49 +0100295 // 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 Gaffiedc7553f2018-11-02 10:39:57 +0100302 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
303}
304
305DeviceVector 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
311sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
Mikhail Naganovbfac5832019-03-05 16:55:28 -0800312 sp<AudioPolicyMix> *mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100313{
François Gaffiec005e562018-11-06 15:04:49 +0100314 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
Eric Laurentaf377772019-03-29 14:50:21 -0700315 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100316 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100317 std::string address;
318 //
François Gaffiec005e562018-11-06 15:04:49 +0100319 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
320 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100321 //
François Gaffiec005e562018-11-06 15:04:49 +0100322 // 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 Gaffiedc7553f2018-11-02 10:39:57 +0100335 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 Gaffiec005e562018-11-06 15:04:49 +0100345 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100346}
347
348void 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 Gaffief1e95082018-11-02 13:53:31 +0100356void 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
367bool 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 }
jiabin12dc6b02019-10-01 09:38:30 -0700373 // FIXME: stop using deviceTypesFromBitMask when the interface is ready
374 getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
François Gaffief1e95082018-11-02 13:53:31 +0100375 return true;
376}
377
François Gaffie20f06f92015-03-24 09:01:14 +0100378template <>
Mikhail Naganove13c6792019-05-14 10:32:51 -0700379EngineInterface *Engine::queryInterface()
François Gaffie20f06f92015-03-24 09:01:14 +0100380{
François Gaffiedc7553f2018-11-02 10:39:57 +0100381 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100382}
383
384template <>
385AudioPolicyPluginInterface *Engine::queryInterface()
386{
François Gaffiedc7553f2018-11-02 10:39:57 +0100387 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100388}
389
390} // namespace audio_policy
391} // namespace android
392
393