blob: cb45fcf5adb8b61e9b227d121a2bca9bd5a42451 [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
36using std::string;
37using std::map;
38
François Gaffief19cf792018-05-30 17:22:17 +020039namespace android {
40namespace audio_policy {
41
François Gaffie20f06f92015-03-24 09:01:14 +010042template <>
François Gaffie20f06f92015-03-24 09:01:14 +010043StreamCollection &Engine::getCollection<audio_stream_type_t>()
44{
45 return mStreamCollection;
46}
47template <>
François Gaffie20f06f92015-03-24 09:01:14 +010048InputSourceCollection &Engine::getCollection<audio_source_t>()
49{
50 return mInputSourceCollection;
51}
52
53template <>
François Gaffie20f06f92015-03-24 09:01:14 +010054const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
55{
56 return mStreamCollection;
57}
58template <>
François Gaffie20f06f92015-03-24 09:01:14 +010059const InputSourceCollection &Engine::getCollection<audio_source_t>() const
60{
61 return mInputSourceCollection;
62}
63
François Gaffiedc7553f2018-11-02 10:39:57 +010064Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
François Gaffie20f06f92015-03-24 09:01:14 +010065{
François Gaffiedc7553f2018-11-02 10:39:57 +010066 status_t loadResult = loadAudioPolicyEngineConfig();
67 if (loadResult < 0) {
68 ALOGE("Policy Engine configuration is invalid.");
69 }
François Gaffie20f06f92015-03-24 09:01:14 +010070}
71
72Engine::~Engine()
73{
François Gaffie20f06f92015-03-24 09:01:14 +010074 mStreamCollection.clear();
75 mInputSourceCollection.clear();
François Gaffie20f06f92015-03-24 09:01:14 +010076}
77
François Gaffie20f06f92015-03-24 09:01:14 +010078status_t Engine::initCheck()
79{
François Gaffiedc7553f2018-11-02 10:39:57 +010080 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
François Gaffie0f17ab72015-05-13 18:13:00 +020081 ALOGE("%s: could not start Policy PFW", __FUNCTION__);
François Gaffie0f17ab72015-05-13 18:13:00 +020082 return NO_INIT;
83 }
François Gaffiedc7553f2018-11-02 10:39:57 +010084 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +010085}
86
François Gaffie20f06f92015-03-24 09:01:14 +010087template <typename Key>
88Element<Key> *Engine::getFromCollection(const Key &key) const
89{
90 const Collection<Key> collection = getCollection<Key>();
91 return collection.get(key);
92}
93
94template <typename Key>
95status_t Engine::add(const std::string &name, const Key &key)
96{
97 Collection<Key> &collection = getCollection<Key>();
98 return collection.add(name, key);
99}
100
François Gaffie20f06f92015-03-24 09:01:14 +0100101template <typename Property, typename Key>
102Property Engine::getPropertyForKey(Key key) const
103{
104 Element<Key> *element = getFromCollection<Key>(key);
105 if (element == NULL) {
106 ALOGE("%s: Element not found within collection", __FUNCTION__);
107 return static_cast<Property>(0);
108 }
109 return element->template get<Property>();
110}
111
François Gaffiedc7553f2018-11-02 10:39:57 +0100112bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
113 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100114{
François Gaffiedc7553f2018-11-02 10:39:57 +0100115 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
Eric Laurentf5aa58d2019-02-22 18:20:11 -0800116 switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100117 return true;
118 }
119 return false;
120}
121
François Gaffie20f06f92015-03-24 09:01:14 +0100122template <typename Property, typename Key>
123bool Engine::setPropertyForKey(const Property &property, const Key &key)
124{
125 Element<Key> *element = getFromCollection<Key>(key);
126 if (element == NULL) {
127 ALOGE("%s: Element not found within collection", __FUNCTION__);
128 return BAD_VALUE;
129 }
130 return element->template set<Property>(property) == NO_ERROR;
131}
132
François Gaffie20f06f92015-03-24 09:01:14 +0100133status_t Engine::setPhoneState(audio_mode_t mode)
134{
François Gaffiedc7553f2018-11-02 10:39:57 +0100135 status_t status = mPolicyParameterMgr->setPhoneState(mode);
136 if (status != NO_ERROR) {
137 return status;
138 }
139 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100140}
141
142audio_mode_t Engine::getPhoneState() const
143{
144 return mPolicyParameterMgr->getPhoneState();
145}
146
147status_t Engine::setForceUse(audio_policy_force_use_t usage,
148 audio_policy_forced_cfg_t config)
149{
François Gaffiedc7553f2018-11-02 10:39:57 +0100150 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
151 if (status != NO_ERROR) {
152 return status;
153 }
154 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100155}
156
157audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
158{
159 return mPolicyParameterMgr->getForceUse(usage);
160}
161
François Gaffiea3e696d2015-12-18 09:38:43 +0100162status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
François Gaffie3305c112018-02-22 10:56:49 +0100163 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100164{
François Gaffie3305c112018-02-22 10:56:49 +0100165 mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
166
François Gaffiea3e696d2015-12-18 09:38:43 +0100167 if (audio_is_output_device(devDesc->type())) {
168 return mPolicyParameterMgr->setAvailableOutputDevices(
François Gaffiedc7553f2018-11-02 10:39:57 +0100169 getApmObserver()->getAvailableOutputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100170 } else if (audio_is_input_device(devDesc->type())) {
171 return mPolicyParameterMgr->setAvailableInputDevices(
François Gaffiedc7553f2018-11-02 10:39:57 +0100172 getApmObserver()->getAvailableInputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100173 }
174 return BAD_TYPE;
François Gaffie20f06f92015-03-24 09:01:14 +0100175}
176
François Gaffiedc7553f2018-11-02 10:39:57 +0100177status_t Engine::loadAudioPolicyEngineConfig()
178{
179 auto result = EngineBase::loadAudioPolicyEngineConfig();
180
François Gaffie7188f1a2018-11-02 14:35:42 +0100181 // Custom XML Parsing
182 auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
183 for (auto& criterion : configCriteria) {
184 engineConfig::CriterionType criterionType;
185 for (auto &configCriterionType : configCriterionTypes) {
186 if (configCriterionType.name == criterion.typeName) {
187 criterionType = configCriterionType;
188 break;
189 }
190 }
191 ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
192 criterion.name.c_str());
193 mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
194 criterionType.valuePairs,
195 criterion.defaultLiteralValue);
196 }
197 };
198
199 loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100200 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
201}
202
203DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
204{
205 const auto productStrategies = getProductStrategies();
206 if (productStrategies.find(ps) == productStrategies.end()) {
207 ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
208 return {};
209 }
Eric Laurentaf377772019-03-29 14:50:21 -0700210 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiedc7553f2018-11-02 10:39:57 +0100211 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
212 uint32_t availableOutputDevicesType = availableOutputDevices.types();
213
214 /** This is the only case handled programmatically because the PFW is unable to know the
215 * activity of streams.
216 *
217 * -While media is playing on a remote device, use the the sonification behavior.
218 * Note that we test this usecase before testing if media is playing because
219 * the isStreamActive() method only informs about the activity of a stream, not
220 * if it's for local playback. Note also that we use the same delay between both tests
221 *
222 * -When media is not playing anymore, fall back on the sonification behavior
223 */
224 audio_devices_t devices = AUDIO_DEVICE_NONE;
225 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
226 !is_state_in_call(getPhoneState()) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700227 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100228 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700229 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100230 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100231 product_strategy_t strategyForMedia =
232 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
233 devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
234 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700235 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
236 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100237 // do not route accessibility prompts to a digital output currently configured with a
238 // compressed format as they would likely not be mixed and dropped.
239 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
240 product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
241 devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
242 } else {
243 devices = productStrategies.getDeviceTypesForProductStrategy(ps);
244 }
245 if (devices == AUDIO_DEVICE_NONE ||
246 (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
247 devices = getApmObserver()->getDefaultOutputDevice()->type();
248 ALOGE_IF(devices == AUDIO_DEVICE_NONE, "%s: no valid default device defined", __FUNCTION__);
249 return DeviceVector(getApmObserver()->getDefaultOutputDevice());
250 }
251 if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
252 // We do expect only one device for these types of devices
253 // Criterion device address garantee this one is available
254 // If this criterion is not wished, need to ensure this device is available
255 const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
256 ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
257 return DeviceVector(availableOutputDevices.getDevice(devices,
258 address,
259 AUDIO_FORMAT_DEFAULT));
260 }
261 ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
262 return availableOutputDevices.getDevicesFromTypeMask(devices);
263}
264
265DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
266 const sp<DeviceDescriptor> &preferredDevice,
267 bool fromCache) const
268{
269 // First check for explict routing device
270 if (preferredDevice != nullptr) {
271 ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
272 return DeviceVector(preferredDevice);
273 }
François Gaffiec005e562018-11-06 15:04:49 +0100274 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
Eric Laurentaf377772019-03-29 14:50:21 -0700275 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100276 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100277 //
François Gaffiec005e562018-11-06 15:04:49 +0100278 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
279 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100280 //
François Gaffiec005e562018-11-06 15:04:49 +0100281 // Honor explicit routing requests only if all active clients have a preferred route in which
282 // case the last active client route is used
283 sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
284 if (device != nullptr) {
285 return DeviceVector(device);
286 }
287
François Gaffiedc7553f2018-11-02 10:39:57 +0100288 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
289}
290
291DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
292{
293 auto attributes = EngineBase::getAttributesForStreamType(stream);
294 return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
295}
296
297sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
Mikhail Naganovbfac5832019-03-05 16:55:28 -0800298 sp<AudioPolicyMix> *mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100299{
François Gaffiec005e562018-11-06 15:04:49 +0100300 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
Eric Laurentaf377772019-03-29 14:50:21 -0700301 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100302 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100303 std::string address;
304 //
François Gaffiec005e562018-11-06 15:04:49 +0100305 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
306 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100307 //
François Gaffiec005e562018-11-06 15:04:49 +0100308 // Honor explicit routing requests only if all active clients have a preferred route in which
309 // case the last active client route is used
310 sp<DeviceDescriptor> device =
311 findPreferredDevice(inputs, attr.source, availableInputDevices);
312 if (device != nullptr) {
313 return device;
314 }
315
316 device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix);
317 if (device != nullptr) {
318 return device;
319 }
320
François Gaffiedc7553f2018-11-02 10:39:57 +0100321 audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
322
323 if (audio_is_remote_submix_device(deviceType)) {
324 address = "0";
325 std::size_t pos;
326 std::string tags { attr.tags };
327 if ((pos = tags.find("addr=")) != std::string::npos) {
328 address = tags.substr(pos + std::strlen("addr="));
329 }
330 }
François Gaffiec005e562018-11-06 15:04:49 +0100331 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100332}
333
334void Engine::updateDeviceSelectionCache()
335{
336 for (const auto &iter : getProductStrategies()) {
337 const auto &strategy = iter.second;
338 mDevicesForStrategies[strategy->getId()] = getDevicesForProductStrategy(strategy->getId());
339 }
340}
341
François Gaffief1e95082018-11-02 13:53:31 +0100342void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
343 const std::string &address)
344{
345 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
346 ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
347 strategy);
348 return;
349 }
350 getProductStrategies().at(strategy)->setDeviceAddress(address);
351}
352
353bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio_devices_t devices)
354{
355 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
356 ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
357 return false;
358 }
359 getProductStrategies().at(strategy)->setDeviceTypes(devices);
360 return true;
361}
362
François Gaffie20f06f92015-03-24 09:01:14 +0100363template <>
364AudioPolicyManagerInterface *Engine::queryInterface()
365{
François Gaffiedc7553f2018-11-02 10:39:57 +0100366 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100367}
368
369template <>
370AudioPolicyPluginInterface *Engine::queryInterface()
371{
François Gaffiedc7553f2018-11-02 10:39:57 +0100372 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100373}
374
375} // namespace audio_policy
376} // namespace android
377
378