blob: 1b09e3dcc6e68c1ceb425dae7b1e7bcb50d5270c [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"
28#include "Strategy.h"
29#include "Stream.h"
30#include "InputSource.h"
31#include "Usage.h"
François Gaffiedc7553f2018-11-02 10:39:57 +010032
33#include <EngineConfig.h>
François Gaffie20f06f92015-03-24 09:01:14 +010034#include <policy.h>
François Gaffiec005e562018-11-06 15:04:49 +010035#include <AudioIODescriptorInterface.h>
François Gaffie20f06f92015-03-24 09:01:14 +010036#include <ParameterManagerWrapper.h>
37
38using 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 <>
45StrategyCollection &Engine::getCollection<routing_strategy>()
46{
47 return mStrategyCollection;
48}
49template <>
50StreamCollection &Engine::getCollection<audio_stream_type_t>()
51{
52 return mStreamCollection;
53}
54template <>
55UsageCollection &Engine::getCollection<audio_usage_t>()
56{
57 return mUsageCollection;
58}
59template <>
60InputSourceCollection &Engine::getCollection<audio_source_t>()
61{
62 return mInputSourceCollection;
63}
64
65template <>
66const StrategyCollection &Engine::getCollection<routing_strategy>() const
67{
68 return mStrategyCollection;
69}
70template <>
71const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
72{
73 return mStreamCollection;
74}
75template <>
76const UsageCollection &Engine::getCollection<audio_usage_t>() const
77{
78 return mUsageCollection;
79}
80template <>
81const InputSourceCollection &Engine::getCollection<audio_source_t>() const
82{
83 return mInputSourceCollection;
84}
85
François Gaffiedc7553f2018-11-02 10:39:57 +010086Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
François Gaffie20f06f92015-03-24 09:01:14 +010087{
François Gaffiedc7553f2018-11-02 10:39:57 +010088 status_t loadResult = loadAudioPolicyEngineConfig();
89 if (loadResult < 0) {
90 ALOGE("Policy Engine configuration is invalid.");
91 }
François Gaffie20f06f92015-03-24 09:01:14 +010092}
93
94Engine::~Engine()
95{
96 mStrategyCollection.clear();
97 mStreamCollection.clear();
98 mInputSourceCollection.clear();
99 mUsageCollection.clear();
100}
101
François Gaffie20f06f92015-03-24 09:01:14 +0100102status_t Engine::initCheck()
103{
François Gaffiedc7553f2018-11-02 10:39:57 +0100104 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
François Gaffie0f17ab72015-05-13 18:13:00 +0200105 ALOGE("%s: could not start Policy PFW", __FUNCTION__);
François Gaffie0f17ab72015-05-13 18:13:00 +0200106 return NO_INIT;
107 }
François Gaffiedc7553f2018-11-02 10:39:57 +0100108 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +0100109}
110
François Gaffie20f06f92015-03-24 09:01:14 +0100111template <typename Key>
112Element<Key> *Engine::getFromCollection(const Key &key) const
113{
114 const Collection<Key> collection = getCollection<Key>();
115 return collection.get(key);
116}
117
118template <typename Key>
119status_t Engine::add(const std::string &name, const Key &key)
120{
121 Collection<Key> &collection = getCollection<Key>();
122 return collection.add(name, key);
123}
124
François Gaffie20f06f92015-03-24 09:01:14 +0100125template <typename Property, typename Key>
126Property Engine::getPropertyForKey(Key key) const
127{
128 Element<Key> *element = getFromCollection<Key>(key);
129 if (element == NULL) {
130 ALOGE("%s: Element not found within collection", __FUNCTION__);
131 return static_cast<Property>(0);
132 }
133 return element->template get<Property>();
134}
135
François Gaffiedc7553f2018-11-02 10:39:57 +0100136routing_strategy Engine::getStrategyForUsage(audio_usage_t usage)
François Gaffie20f06f92015-03-24 09:01:14 +0100137{
François Gaffiedc7553f2018-11-02 10:39:57 +0100138 return getPropertyForKey<routing_strategy, audio_usage_t>(usage);
François Gaffie0f17ab72015-05-13 18:13:00 +0200139}
140
François Gaffiedc7553f2018-11-02 10:39:57 +0100141audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
François Gaffie0f17ab72015-05-13 18:13:00 +0200142{
François Gaffiedc7553f2018-11-02 10:39:57 +0100143 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffie20f06f92015-03-24 09:01:14 +0100144
145 /** This is the only case handled programmatically because the PFW is unable to know the
146 * activity of streams.
147 *
148 * -While media is playing on a remote device, use the the sonification behavior.
149 * Note that we test this usecase before testing if media is playing because
150 * the isStreamActive() method only informs about the activity of a stream, not
151 * if it's for local playback. Note also that we use the same delay between both tests
152 *
153 * -When media is not playing anymore, fall back on the sonification behavior
154 */
155 if (strategy == STRATEGY_SONIFICATION_RESPECTFUL &&
156 !is_state_in_call(getPhoneState()) &&
157 !outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
158 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
159 outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100160 return getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_MEDIA);
François Gaffie20f06f92015-03-24 09:01:14 +0100161 }
François Gaffie4ac9d842016-04-12 16:56:35 +0200162 if (strategy == STRATEGY_ACCESSIBILITY &&
163 (outputs.isStreamActive(AUDIO_STREAM_RING) || outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
164 // do not route accessibility prompts to a digital output currently configured with a
165 // compressed format as they would likely not be mixed and dropped.
166 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
François Gaffiedc7553f2018-11-02 10:39:57 +0100167 return getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_SONIFICATION);
François Gaffie4ac9d842016-04-12 16:56:35 +0200168 }
François Gaffiedc7553f2018-11-02 10:39:57 +0100169 return getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
François Gaffie20f06f92015-03-24 09:01:14 +0100170}
171
François Gaffiedc7553f2018-11-02 10:39:57 +0100172bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
173 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100174{
François Gaffiedc7553f2018-11-02 10:39:57 +0100175 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
176 getApmObserver()->getVolumeCurves().switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100177 return true;
178 }
179 return false;
180}
181
François Gaffie20f06f92015-03-24 09:01:14 +0100182template <typename Property, typename Key>
183bool Engine::setPropertyForKey(const Property &property, const Key &key)
184{
185 Element<Key> *element = getFromCollection<Key>(key);
186 if (element == NULL) {
187 ALOGE("%s: Element not found within collection", __FUNCTION__);
188 return BAD_VALUE;
189 }
190 return element->template set<Property>(property) == NO_ERROR;
191}
192
François Gaffie20f06f92015-03-24 09:01:14 +0100193status_t Engine::setPhoneState(audio_mode_t mode)
194{
François Gaffiedc7553f2018-11-02 10:39:57 +0100195 status_t status = mPolicyParameterMgr->setPhoneState(mode);
196 if (status != NO_ERROR) {
197 return status;
198 }
199 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100200}
201
202audio_mode_t Engine::getPhoneState() const
203{
204 return mPolicyParameterMgr->getPhoneState();
205}
206
207status_t Engine::setForceUse(audio_policy_force_use_t usage,
208 audio_policy_forced_cfg_t config)
209{
François Gaffiedc7553f2018-11-02 10:39:57 +0100210 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
211 if (status != NO_ERROR) {
212 return status;
213 }
214 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100215}
216
217audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
218{
219 return mPolicyParameterMgr->getForceUse(usage);
220}
221
François Gaffiea3e696d2015-12-18 09:38:43 +0100222status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
François Gaffie3305c112018-02-22 10:56:49 +0100223 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100224{
François Gaffie3305c112018-02-22 10:56:49 +0100225 mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
226
François Gaffiea3e696d2015-12-18 09:38:43 +0100227 if (audio_is_output_device(devDesc->type())) {
228 return mPolicyParameterMgr->setAvailableOutputDevices(
François Gaffiedc7553f2018-11-02 10:39:57 +0100229 getApmObserver()->getAvailableOutputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100230 } else if (audio_is_input_device(devDesc->type())) {
231 return mPolicyParameterMgr->setAvailableInputDevices(
François Gaffiedc7553f2018-11-02 10:39:57 +0100232 getApmObserver()->getAvailableInputDevices().types());
François Gaffiea3e696d2015-12-18 09:38:43 +0100233 }
234 return BAD_TYPE;
François Gaffie20f06f92015-03-24 09:01:14 +0100235}
236
François Gaffiedc7553f2018-11-02 10:39:57 +0100237status_t Engine::loadAudioPolicyEngineConfig()
238{
239 auto result = EngineBase::loadAudioPolicyEngineConfig();
240
François Gaffie7188f1a2018-11-02 14:35:42 +0100241 // Custom XML Parsing
242 auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
243 for (auto& criterion : configCriteria) {
244 engineConfig::CriterionType criterionType;
245 for (auto &configCriterionType : configCriterionTypes) {
246 if (configCriterionType.name == criterion.typeName) {
247 criterionType = configCriterionType;
248 break;
249 }
250 }
251 ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
252 criterion.name.c_str());
253 mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
254 criterionType.valuePairs,
255 criterion.defaultLiteralValue);
256 }
257 };
258
259 loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100260 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
261}
262
263DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
264{
265 const auto productStrategies = getProductStrategies();
266 if (productStrategies.find(ps) == productStrategies.end()) {
267 ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
268 return {};
269 }
270 const DeviceVector &availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
271 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
272 uint32_t availableOutputDevicesType = availableOutputDevices.types();
273
274 /** This is the only case handled programmatically because the PFW is unable to know the
275 * activity of streams.
276 *
277 * -While media is playing on a remote device, use the the sonification behavior.
278 * Note that we test this usecase before testing if media is playing because
279 * the isStreamActive() method only informs about the activity of a stream, not
280 * if it's for local playback. Note also that we use the same delay between both tests
281 *
282 * -When media is not playing anymore, fall back on the sonification behavior
283 */
284 audio_devices_t devices = AUDIO_DEVICE_NONE;
285 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
286 !is_state_in_call(getPhoneState()) &&
287 !outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
288 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
289 outputs.isStreamActive(AUDIO_STREAM_MUSIC,
290 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
291 product_strategy_t strategyForMedia =
292 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
293 devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
294 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
295 (outputs.isStreamActive(AUDIO_STREAM_RING) ||
296 outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
297 // do not route accessibility prompts to a digital output currently configured with a
298 // compressed format as they would likely not be mixed and dropped.
299 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
300 product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
301 devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
302 } else {
303 devices = productStrategies.getDeviceTypesForProductStrategy(ps);
304 }
305 if (devices == AUDIO_DEVICE_NONE ||
306 (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
307 devices = getApmObserver()->getDefaultOutputDevice()->type();
308 ALOGE_IF(devices == AUDIO_DEVICE_NONE, "%s: no valid default device defined", __FUNCTION__);
309 return DeviceVector(getApmObserver()->getDefaultOutputDevice());
310 }
311 if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
312 // We do expect only one device for these types of devices
313 // Criterion device address garantee this one is available
314 // If this criterion is not wished, need to ensure this device is available
315 const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
316 ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
317 return DeviceVector(availableOutputDevices.getDevice(devices,
318 address,
319 AUDIO_FORMAT_DEFAULT));
320 }
321 ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
322 return availableOutputDevices.getDevicesFromTypeMask(devices);
323}
324
325DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
326 const sp<DeviceDescriptor> &preferredDevice,
327 bool fromCache) const
328{
329 // First check for explict routing device
330 if (preferredDevice != nullptr) {
331 ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
332 return DeviceVector(preferredDevice);
333 }
François Gaffiec005e562018-11-06 15:04:49 +0100334 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
335 const DeviceVector &availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
336 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100337 //
François Gaffiec005e562018-11-06 15:04:49 +0100338 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
339 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100340 //
François Gaffiec005e562018-11-06 15:04:49 +0100341 // Honor explicit routing requests only if all active clients have a preferred route in which
342 // case the last active client route is used
343 sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
344 if (device != nullptr) {
345 return DeviceVector(device);
346 }
347
François Gaffiedc7553f2018-11-02 10:39:57 +0100348 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
349}
350
351DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
352{
353 auto attributes = EngineBase::getAttributesForStreamType(stream);
354 return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
355}
356
357sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
François Gaffiec005e562018-11-06 15:04:49 +0100358 AudioMix **mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100359{
François Gaffiec005e562018-11-06 15:04:49 +0100360 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
361 const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices();
362 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100363 std::string address;
364 //
François Gaffiec005e562018-11-06 15:04:49 +0100365 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
366 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100367 //
François Gaffiec005e562018-11-06 15:04:49 +0100368 // Honor explicit routing requests only if all active clients have a preferred route in which
369 // case the last active client route is used
370 sp<DeviceDescriptor> device =
371 findPreferredDevice(inputs, attr.source, availableInputDevices);
372 if (device != nullptr) {
373 return device;
374 }
375
376 device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix);
377 if (device != nullptr) {
378 return device;
379 }
380
François Gaffiedc7553f2018-11-02 10:39:57 +0100381 audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
382
383 if (audio_is_remote_submix_device(deviceType)) {
384 address = "0";
385 std::size_t pos;
386 std::string tags { attr.tags };
387 if ((pos = tags.find("addr=")) != std::string::npos) {
388 address = tags.substr(pos + std::strlen("addr="));
389 }
390 }
François Gaffiec005e562018-11-06 15:04:49 +0100391 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100392}
393
394void Engine::updateDeviceSelectionCache()
395{
396 for (const auto &iter : getProductStrategies()) {
397 const auto &strategy = iter.second;
398 mDevicesForStrategies[strategy->getId()] = getDevicesForProductStrategy(strategy->getId());
399 }
400}
401
François Gaffief1e95082018-11-02 13:53:31 +0100402void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
403 const std::string &address)
404{
405 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
406 ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
407 strategy);
408 return;
409 }
410 getProductStrategies().at(strategy)->setDeviceAddress(address);
411}
412
413bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio_devices_t devices)
414{
415 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
416 ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
417 return false;
418 }
419 getProductStrategies().at(strategy)->setDeviceTypes(devices);
420 return true;
421}
422
François Gaffie20f06f92015-03-24 09:01:14 +0100423template <>
424AudioPolicyManagerInterface *Engine::queryInterface()
425{
François Gaffiedc7553f2018-11-02 10:39:57 +0100426 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100427}
428
429template <>
430AudioPolicyPluginInterface *Engine::queryInterface()
431{
François Gaffiedc7553f2018-11-02 10:39:57 +0100432 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100433}
434
435} // namespace audio_policy
436} // namespace android
437
438