1 /*
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 "Stream.h"
29 #include "InputSource.h"
30
31 #include <EngineConfig.h>
32 #include <policy.h>
33 #include <AudioIODescriptorInterface.h>
34 #include <ParameterManagerWrapper.h>
35 #include <media/AudioContainers.h>
36
37 #include <media/TypeConverter.h>
38
39 using std::string;
40 using std::map;
41
42 namespace android {
43 namespace audio_policy {
44
45 template <>
getCollection()46 StreamCollection &Engine::getCollection<audio_stream_type_t>()
47 {
48 return mStreamCollection;
49 }
50 template <>
getCollection()51 InputSourceCollection &Engine::getCollection<audio_source_t>()
52 {
53 return mInputSourceCollection;
54 }
55
56 template <>
getCollection() const57 const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
58 {
59 return mStreamCollection;
60 }
61 template <>
getCollection() const62 const InputSourceCollection &Engine::getCollection<audio_source_t>() const
63 {
64 return mInputSourceCollection;
65 }
66
Engine()67 Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
68 {
69 status_t loadResult = loadAudioPolicyEngineConfig();
70 if (loadResult < 0) {
71 ALOGE("Policy Engine configuration is invalid.");
72 }
73 }
74
~Engine()75 Engine::~Engine()
76 {
77 mStreamCollection.clear();
78 mInputSourceCollection.clear();
79 }
80
initCheck()81 status_t Engine::initCheck()
82 {
83 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());
86 return NO_INIT;
87 }
88 return EngineBase::initCheck();
89 }
90
91 template <typename Key>
getFromCollection(const Key & key) const92 Element<Key> *Engine::getFromCollection(const Key &key) const
93 {
94 const Collection<Key> collection = getCollection<Key>();
95 return collection.get(key);
96 }
97
98 template <typename Key>
add(const std::string & name,const Key & key)99 status_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
105 template <typename Property, typename Key>
getPropertyForKey(Key key) const106 Property 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
setVolumeProfileForStream(const audio_stream_type_t & stream,const audio_stream_type_t & profile)116 bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
117 const audio_stream_type_t &profile)
118 {
119 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
120 switchVolumeCurve(profile, stream);
121 return true;
122 }
123 return false;
124 }
125
126 template <typename Property, typename Key>
setPropertyForKey(const Property & property,const Key & key)127 bool 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 false;
133 }
134 return element->template set<Property>(property) == NO_ERROR;
135 }
136
setPhoneState(audio_mode_t mode)137 status_t Engine::setPhoneState(audio_mode_t mode)
138 {
139 status_t status = mPolicyParameterMgr->setPhoneState(mode);
140 if (status != NO_ERROR) {
141 return status;
142 }
143 return EngineBase::setPhoneState(mode);
144 }
145
getPhoneState() const146 audio_mode_t Engine::getPhoneState() const
147 {
148 return mPolicyParameterMgr->getPhoneState();
149 }
150
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)151 status_t Engine::setForceUse(audio_policy_force_use_t usage,
152 audio_policy_forced_cfg_t config)
153 {
154 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
155 if (status != NO_ERROR) {
156 return status;
157 }
158 return EngineBase::setForceUse(usage, config);
159 }
160
getForceUse(audio_policy_force_use_t usage) const161 audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
162 {
163 return mPolicyParameterMgr->getForceUse(usage);
164 }
165
setDeviceConnectionState(const sp<DeviceDescriptor> device,audio_policy_dev_state_t state)166 status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
167 audio_policy_dev_state_t state)
168 {
169 mPolicyParameterMgr->setDeviceConnectionState(
170 device->type(), device->address().c_str(), state);
171 if (audio_is_output_device(device->type())) {
172 // FIXME: Use DeviceTypeSet when the interface is ready
173 return mPolicyParameterMgr->setAvailableOutputDevices(
174 deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
175 } else if (audio_is_input_device(device->type())) {
176 // FIXME: Use DeviceTypeSet when the interface is ready
177 return mPolicyParameterMgr->setAvailableInputDevices(
178 deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
179 }
180 return EngineBase::setDeviceConnectionState(device, state);
181 }
182
loadAudioPolicyEngineConfig()183 status_t Engine::loadAudioPolicyEngineConfig()
184 {
185 auto result = EngineBase::loadAudioPolicyEngineConfig();
186
187 // 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);
206 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
207 }
208
getDevicesForProductStrategy(product_strategy_t ps) const209 DeviceVector 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 }
216 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
217 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
218 DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
219
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 */
230 DeviceTypeSet deviceTypes;
231 if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
232 !is_state_in_call(getPhoneState()) &&
233 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
234 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
235 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
236 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
237 product_strategy_t strategyForMedia =
238 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
239 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
240 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
241 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
242 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
243 // 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);
247 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
248 } else {
249 deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
250 }
251 if (deviceTypes.empty() ||
252 Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
253 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
254 ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
255 return DeviceVector(defaultDevice);
256 }
257 if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
258 deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
259 // 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());
263 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);
267 if (busDevice == nullptr) {
268 ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
269 dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
270 auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
271 ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
272 return DeviceVector(defaultDevice);
273 }
274 return DeviceVector(busDevice);
275 }
276 ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
277 return availableOutputDevices.getDevicesFromTypes(deviceTypes);
278 }
279
getOutputDevicesForAttributes(const audio_attributes_t & attributes,const sp<DeviceDescriptor> & preferredDevice,bool fromCache) const280 DeviceVector 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 }
289 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
290 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
291 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
292 //
293 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
294 // be by APM?
295 //
296 // 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
303 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
304 }
305
getOutputDevicesForStream(audio_stream_type_t stream,bool fromCache) const306 DeviceVector 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
getInputDeviceForAttributes(const audio_attributes_t & attr,sp<AudioPolicyMix> * mix) const312 sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
313 sp<AudioPolicyMix> *mix) const
314 {
315 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
316 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
317 const auto &inputs = getApmObserver()->getInputs();
318 std::string address;
319 //
320 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
321 // first as it used to be by APM?
322 //
323 // 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
336 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 }
346 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
347 }
348
updateDeviceSelectionCache()349 void 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
setDeviceAddressForProductStrategy(product_strategy_t strategy,const std::string & address)357 void 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
setDeviceTypesForProductStrategy(product_strategy_t strategy,audio_devices_t devices)368 bool 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 }
374 // FIXME: stop using deviceTypesFromBitMask when the interface is ready
375 getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
376 return true;
377 }
378
379 template <>
queryInterface()380 EngineInterface *Engine::queryInterface()
381 {
382 return this;
383 }
384
385 template <>
queryInterface()386 AudioPolicyPluginInterface *Engine::queryInterface()
387 {
388 return this;
389 }
390
391 } // namespace audio_policy
392 } // namespace android
393
394
395