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
36 using std::string;
37 using std::map;
38
39 namespace android {
40 namespace audio_policy {
41
42 template <>
getCollection()43 StreamCollection &Engine::getCollection<audio_stream_type_t>()
44 {
45 return mStreamCollection;
46 }
47 template <>
getCollection()48 InputSourceCollection &Engine::getCollection<audio_source_t>()
49 {
50 return mInputSourceCollection;
51 }
52
53 template <>
getCollection() const54 const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
55 {
56 return mStreamCollection;
57 }
58 template <>
getCollection() const59 const InputSourceCollection &Engine::getCollection<audio_source_t>() const
60 {
61 return mInputSourceCollection;
62 }
63
Engine()64 Engine::Engine() : mPolicyParameterMgr(new ParameterManagerWrapper())
65 {
66 status_t loadResult = loadAudioPolicyEngineConfig();
67 if (loadResult < 0) {
68 ALOGE("Policy Engine configuration is invalid.");
69 }
70 }
71
~Engine()72 Engine::~Engine()
73 {
74 mStreamCollection.clear();
75 mInputSourceCollection.clear();
76 }
77
initCheck()78 status_t Engine::initCheck()
79 {
80 if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
81 ALOGE("%s: could not start Policy PFW", __FUNCTION__);
82 return NO_INIT;
83 }
84 return EngineBase::initCheck();
85 }
86
87 template <typename Key>
getFromCollection(const Key & key) const88 Element<Key> *Engine::getFromCollection(const Key &key) const
89 {
90 const Collection<Key> collection = getCollection<Key>();
91 return collection.get(key);
92 }
93
94 template <typename Key>
add(const std::string & name,const Key & key)95 status_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
101 template <typename Property, typename Key>
getPropertyForKey(Key key) const102 Property 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
setVolumeProfileForStream(const audio_stream_type_t & stream,const audio_stream_type_t & profile)112 bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
113 const audio_stream_type_t &profile)
114 {
115 if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
116 switchVolumeCurve(profile, stream);
117 return true;
118 }
119 return false;
120 }
121
122 template <typename Property, typename Key>
setPropertyForKey(const Property & property,const Key & key)123 bool 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
setPhoneState(audio_mode_t mode)133 status_t Engine::setPhoneState(audio_mode_t mode)
134 {
135 status_t status = mPolicyParameterMgr->setPhoneState(mode);
136 if (status != NO_ERROR) {
137 return status;
138 }
139 return EngineBase::setPhoneState(mode);
140 }
141
getPhoneState() const142 audio_mode_t Engine::getPhoneState() const
143 {
144 return mPolicyParameterMgr->getPhoneState();
145 }
146
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)147 status_t Engine::setForceUse(audio_policy_force_use_t usage,
148 audio_policy_forced_cfg_t config)
149 {
150 status_t status = mPolicyParameterMgr->setForceUse(usage, config);
151 if (status != NO_ERROR) {
152 return status;
153 }
154 return EngineBase::setForceUse(usage, config);
155 }
156
getForceUse(audio_policy_force_use_t usage) const157 audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
158 {
159 return mPolicyParameterMgr->getForceUse(usage);
160 }
161
setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,audio_policy_dev_state_t state)162 status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
163 audio_policy_dev_state_t state)
164 {
165 mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
166
167 if (audio_is_output_device(devDesc->type())) {
168 return mPolicyParameterMgr->setAvailableOutputDevices(
169 getApmObserver()->getAvailableOutputDevices().types());
170 } else if (audio_is_input_device(devDesc->type())) {
171 return mPolicyParameterMgr->setAvailableInputDevices(
172 getApmObserver()->getAvailableInputDevices().types());
173 }
174 return BAD_TYPE;
175 }
176
loadAudioPolicyEngineConfig()177 status_t Engine::loadAudioPolicyEngineConfig()
178 {
179 auto result = EngineBase::loadAudioPolicyEngineConfig();
180
181 // 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);
200 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
201 }
202
getDevicesForProductStrategy(product_strategy_t ps) const203 DeviceVector 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 }
210 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
211 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()) &&
227 !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
228 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
229 outputs.isActive(toVolumeSource(AUDIO_STREAM_MUSIC),
230 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
231 product_strategy_t strategyForMedia =
232 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
233 devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
234 } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
235 (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
236 outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
237 // 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
getOutputDevicesForAttributes(const audio_attributes_t & attributes,const sp<DeviceDescriptor> & preferredDevice,bool fromCache) const265 DeviceVector 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 }
274 product_strategy_t strategy = getProductStrategyForAttributes(attributes);
275 const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
276 const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
277 //
278 // @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
279 // be by APM?
280 //
281 // 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
288 return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
289 }
290
getOutputDevicesForStream(audio_stream_type_t stream,bool fromCache) const291 DeviceVector 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
getInputDeviceForAttributes(const audio_attributes_t & attr,sp<AudioPolicyMix> * mix) const297 sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
298 sp<AudioPolicyMix> *mix) const
299 {
300 const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
301 const auto availableInputDevices = getApmObserver()->getAvailableInputDevices();
302 const auto &inputs = getApmObserver()->getInputs();
303 std::string address;
304 //
305 // Explicit Routing ??? what is the priority of explicit routing? Shall it be considered
306 // first as it used to be by APM?
307 //
308 // 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
321 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 }
331 return availableInputDevices.getDevice(deviceType, String8(address.c_str()), AUDIO_FORMAT_DEFAULT);
332 }
333
updateDeviceSelectionCache()334 void 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
setDeviceAddressForProductStrategy(product_strategy_t strategy,const std::string & address)342 void 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
setDeviceTypesForProductStrategy(product_strategy_t strategy,audio_devices_t devices)353 bool 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
363 template <>
queryInterface()364 AudioPolicyManagerInterface *Engine::queryInterface()
365 {
366 return this;
367 }
368
369 template <>
queryInterface()370 AudioPolicyPluginInterface *Engine::queryInterface()
371 {
372 return this;
373 }
374
375 } // namespace audio_policy
376 } // namespace android
377
378
379