• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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