blob: 7e5c5e392c9fcaa4f4010472cc0d86eec3ba4281 [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 Gaffieab1837a2019-10-15 10:48:50 +020083 std::string error;
84 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
85 ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
François Gaffie0f17ab72015-05-13 18:13:00 +020086 return NO_INIT;
87 }
François Gaffiedc7553f2018-11-02 10:39:57 +010088 return EngineBase::initCheck();
François Gaffie20f06f92015-03-24 09:01:14 +010089}
90
François Gaffie20f06f92015-03-24 09:01:14 +010091template <typename Key>
92Element<Key> *Engine::getFromCollection(const Key &key) const
93{
94 const Collection<Key> collection = getCollection<Key>();
95 return collection.get(key);
96}
97
98template <typename Key>
99status_t Engine::add(const std::string &name, const Key &key)
100{
101 Collection<Key> &collection = getCollection<Key>();
102 return collection.add(name, key);
103}
104
François Gaffie20f06f92015-03-24 09:01:14 +0100105template <typename Property, typename Key>
106Property Engine::getPropertyForKey(Key key) const
107{
108 Element<Key> *element = getFromCollection<Key>(key);
109 if (element == NULL) {
110 ALOGE("%s: Element not found within collection", __FUNCTION__);
111 return static_cast<Property>(0);
112 }
113 return element->template get<Property>();
114}
115
François Gaffiedc7553f2018-11-02 10:39:57 +0100116bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
117 const audio_stream_type_t &profile)
François Gaffied1ab2bd2015-12-02 18:20:06 +0100118{
François Gaffiedc7553f2018-11-02 10:39:57 +0100119 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
Eric Laurentf5aa58d2019-02-22 18:20:11 -0800120 switchVolumeCurve(profile, stream);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100121 return true;
122 }
123 return false;
124}
125
François Gaffie20f06f92015-03-24 09:01:14 +0100126template <typename Property, typename Key>
127bool Engine::setPropertyForKey(const Property &property, const Key &key)
128{
129 Element<Key> *element = getFromCollection<Key>(key);
130 if (element == NULL) {
131 ALOGE("%s: Element not found within collection", __FUNCTION__);
132 return BAD_VALUE;
133 }
134 return element->template set<Property>(property) == NO_ERROR;
135}
136
François Gaffie20f06f92015-03-24 09:01:14 +0100137status_t Engine::setPhoneState(audio_mode_t mode)
138{
François Gaffiedc7553f2018-11-02 10:39:57 +0100139 status_t status = mPolicyParameterMgr->setPhoneState(mode);
140 if (status != NO_ERROR) {
141 return status;
142 }
143 return EngineBase::setPhoneState(mode);
François Gaffie20f06f92015-03-24 09:01:14 +0100144}
145
146audio_mode_t Engine::getPhoneState() const
147{
148 return mPolicyParameterMgr->getPhoneState();
149}
150
151status_t Engine::setForceUse(audio_policy_force_use_t usage,
152 audio_policy_forced_cfg_t config)
153{
François Gaffiedc7553f2018-11-02 10:39:57 +0100154 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
155 if (status != NO_ERROR) {
156 return status;
157 }
158 return EngineBase::setForceUse(usage, config);
François Gaffie20f06f92015-03-24 09:01:14 +0100159}
160
161audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
162{
163 return mPolicyParameterMgr->getForceUse(usage);
164}
165
François Gaffieab1837a2019-10-15 10:48:50 +0200166status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
François Gaffie3305c112018-02-22 10:56:49 +0100167 audio_policy_dev_state_t state)
François Gaffie20f06f92015-03-24 09:01:14 +0100168{
François Gaffieab1837a2019-10-15 10:48:50 +0200169 mPolicyParameterMgr->setDeviceConnectionState(
170 device->type(), device->address().c_str(), state);
171 if (audio_is_output_device(device->type())) {
jiabin12dc6b02019-10-01 09:38:30 -0700172 // FIXME: Use DeviceTypeSet when the interface is ready
François Gaffiea3e696d2015-12-18 09:38:43 +0100173 return mPolicyParameterMgr->setAvailableOutputDevices(
jiabin12dc6b02019-10-01 09:38:30 -0700174 deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
François Gaffieab1837a2019-10-15 10:48:50 +0200175 } else if (audio_is_input_device(device->type())) {
jiabin12dc6b02019-10-01 09:38:30 -0700176 // FIXME: Use DeviceTypeSet when the interface is ready
François Gaffiea3e696d2015-12-18 09:38:43 +0100177 return mPolicyParameterMgr->setAvailableInputDevices(
jiabin12dc6b02019-10-01 09:38:30 -0700178 deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
François Gaffiea3e696d2015-12-18 09:38:43 +0100179 }
François Gaffieab1837a2019-10-15 10:48:50 +0200180 return EngineBase::setDeviceConnectionState(device, state);
François Gaffie20f06f92015-03-24 09:01:14 +0100181}
182
François Gaffiedc7553f2018-11-02 10:39:57 +0100183status_t Engine::loadAudioPolicyEngineConfig()
184{
185 auto result = EngineBase::loadAudioPolicyEngineConfig();
186
François Gaffie7188f1a2018-11-02 14:35:42 +0100187 // Custom XML Parsing
188 auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
189 for (auto& criterion : configCriteria) {
190 engineConfig::CriterionType criterionType;
191 for (auto &configCriterionType : configCriterionTypes) {
192 if (configCriterionType.name == criterion.typeName) {
193 criterionType = configCriterionType;
194 break;
195 }
196 }
197 ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
198 criterion.name.c_str());
199 mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
200 criterionType.valuePairs,
201 criterion.defaultLiteralValue);
202 }
203 };
204
205 loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100206 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
207}
208
209DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t ps) const
210{
211 const auto productStrategies = getProductStrategies();
212 if (productStrategies.find(ps) == productStrategies.end()) {
213 ALOGE("%s: Trying to get device on invalid strategy %d", __FUNCTION__, ps);
214 return {};
215 }
Eric Laurentaf377772019-03-29 14:50:21 -0700216 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiedc7553f2018-11-02 10:39:57 +0100217 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
jiabin12dc6b02019-10-01 09:38:30 -0700218 DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
François Gaffiedc7553f2018-11-02 10:39:57 +0100219
220 /** This is the only case handled programmatically because the PFW is unable to know the
221 * activity of streams.
222 *
223 * -While media is playing on a remote device, use the the sonification behavior.
224 * Note that we test this usecase before testing if media is playing because
225 * the isStreamActive() method only informs about the activity of a stream, not
226 * if it's for local playback. Note also that we use the same delay between both tests
227 *
228 * -When media is not playing anymore, fall back on the sonification behavior
229 */
jiabin12dc6b02019-10-01 09:38:30 -0700230 DeviceTypeSet deviceTypes;
François Gaffiedc7553f2018-11-02 10:39:57 +0100231 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
232 !is_state_in_call(getPhoneState()) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700233 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100234 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700235 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
François Gaffie1c878552018-11-22 16:53:21 +0100236 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100237 product_strategy_t strategyForMedia =
238 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
jiabin12dc6b02019-10-01 09:38:30 -0700239 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
François Gaffiedc7553f2018-11-02 10:39:57 +0100240 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
Eric Laurent83d17c22019-04-02 17:10:01 -0700241 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
242 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100243 // do not route accessibility prompts to a digital output currently configured with a
244 // compressed format as they would likely not be mixed and dropped.
245 // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
246 product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
jiabin12dc6b02019-10-01 09:38:30 -0700247 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
François Gaffiedc7553f2018-11-02 10:39:57 +0100248 } else {
jiabin12dc6b02019-10-01 09:38:30 -0700249 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
François Gaffiedc7553f2018-11-02 10:39:57 +0100250 }
jiabin12dc6b02019-10-01 09:38:30 -0700251 if (deviceTypes.empty() ||
252 Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
François Gaffiec60c3692019-08-09 15:41:24 +0200253 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
254 ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
255 return DeviceVector(defaultDevice);
François Gaffiedc7553f2018-11-02 10:39:57 +0100256 }
jiabin12dc6b02019-10-01 09:38:30 -0700257 if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
258 deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
François Gaffiedc7553f2018-11-02 10:39:57 +0100259 // We do expect only one device for these types of devices
260 // Criterion device address garantee this one is available
261 // If this criterion is not wished, need to ensure this device is available
262 const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
jiabin12dc6b02019-10-01 09:38:30 -0700263 ALOGV("%s:device %s %s %d",
264 __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
265 auto busDevice = availableOutputDevices.getDevice(
266 *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
François Gaffiec60c3692019-08-09 15:41:24 +0200267 if (busDevice == nullptr) {
jiabin12dc6b02019-10-01 09:38:30 -0700268 ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
269 dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
François Gaffiec60c3692019-08-09 15:41:24 +0200270 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
271 ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
272 return DeviceVector(defaultDevice);
273 }
jiabin12dc6b02019-10-01 09:38:30 -0700274 return DeviceVector(busDevice);
François Gaffiedc7553f2018-11-02 10:39:57 +0100275 }
jiabin12dc6b02019-10-01 09:38:30 -0700276 ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
277 return availableOutputDevices.getDevicesFromTypes(deviceTypes);
François Gaffiedc7553f2018-11-02 10:39:57 +0100278}
279
280DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
281 const sp<DeviceDescriptor> &preferredDevice,
282 bool fromCache) const
283{
284 // First check for explict routing device
285 if (preferredDevice != nullptr) {
286 ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
287 return DeviceVector(preferredDevice);
288 }
François Gaffiec005e562018-11-06 15:04:49 +0100289 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
Eric Laurentaf377772019-03-29 14:50:21 -0700290 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100291 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100292 //
François Gaffiec005e562018-11-06 15:04:49 +0100293 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
294 // be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100295 //
François Gaffiec005e562018-11-06 15:04:49 +0100296 // Honor explicit routing requests only if all active clients have a preferred route in which
297 // case the last active client route is used
298 sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices);
299 if (device != nullptr) {
300 return DeviceVector(device);
301 }
302
François Gaffiedc7553f2018-11-02 10:39:57 +0100303 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
304}
305
306DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
307{
308 auto attributes = EngineBase::getAttributesForStreamType(stream);
309 return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
310}
311
312sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
Mikhail Naganovbfac5832019-03-05 16:55:28 -0800313 sp<AudioPolicyMix> *mix) const
François Gaffiedc7553f2018-11-02 10:39:57 +0100314{
François Gaffiec005e562018-11-06 15:04:49 +0100315 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
Eric Laurentaf377772019-03-29 14:50:21 -0700316 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
François Gaffiec005e562018-11-06 15:04:49 +0100317 const auto &inputs = getApmObserver()->getInputs();
François Gaffiedc7553f2018-11-02 10:39:57 +0100318 std::string address;
319 //
François Gaffiec005e562018-11-06 15:04:49 +0100320 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
321 // first as it used to be by APM?
François Gaffiedc7553f2018-11-02 10:39:57 +0100322 //
François Gaffiec005e562018-11-06 15:04:49 +0100323 // Honor explicit routing requests only if all active clients have a preferred route in which
324 // case the last active client route is used
325 sp<DeviceDescriptor> device =
326 findPreferredDevice(inputs, attr.source, availableInputDevices);
327 if (device != nullptr) {
328 return device;
329 }
330
331 device = policyMixes.getDeviceAndMixForInputSource(attr.source, availableInputDevices, mix);
332 if (device != nullptr) {
333 return device;
334 }
335
François Gaffiedc7553f2018-11-02 10:39:57 +0100336 audio_devices_t deviceType = getPropertyForKey<audio_devices_t, audio_source_t>(attr.source);
337
338 if (audio_is_remote_submix_device(deviceType)) {
339 address = "0";
340 std::size_t pos;
341 std::string tags { attr.tags };
342 if ((pos = tags.find("addr=")) != std::string::npos) {
343 address = tags.substr(pos + std::strlen("addr="));
344 }
345 }
François Gaffiec005e562018-11-06 15:04:49 +0100346 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
François Gaffiedc7553f2018-11-02 10:39:57 +0100347}
348
349void Engine::updateDeviceSelectionCache()
350{
351 for (const auto &iter : getProductStrategies()) {
352 const auto &strategy = iter.second;
353 mDevicesForStrategies[strategy->getId()] = getDevicesForProductStrategy(strategy->getId());
354 }
355}
356
François Gaffief1e95082018-11-02 13:53:31 +0100357void Engine::setDeviceAddressForProductStrategy(product_strategy_t strategy,
358 const std::string &address)
359{
360 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
361 ALOGE("%s: Trying to set address %s on invalid strategy %d", __FUNCTION__, address.c_str(),
362 strategy);
363 return;
364 }
365 getProductStrategies().at(strategy)->setDeviceAddress(address);
366}
367
368bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio_devices_t devices)
369{
370 if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
371 ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
372 return false;
373 }
jiabin12dc6b02019-10-01 09:38:30 -0700374 // FIXME: stop using deviceTypesFromBitMask when the interface is ready
375 getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
François Gaffief1e95082018-11-02 13:53:31 +0100376 return true;
377}
378
François Gaffie20f06f92015-03-24 09:01:14 +0100379template <>
Mikhail Naganove13c6792019-05-14 10:32:51 -0700380EngineInterface *Engine::queryInterface()
François Gaffie20f06f92015-03-24 09:01:14 +0100381{
François Gaffiedc7553f2018-11-02 10:39:57 +0100382 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100383}
384
385template <>
386AudioPolicyPluginInterface *Engine::queryInterface()
387{
François Gaffiedc7553f2018-11-02 10:39:57 +0100388 return this;
François Gaffie20f06f92015-03-24 09:01:14 +0100389}
390
391} // namespace audio_policy
392} // namespace android
393
394