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