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 "Strategy.h"
29#include "Stream.h"
30#include "InputSource.h"
31#include "Usage.h"
32#include <policy.h>
33#include <ParameterManagerWrapper.h>
34
35using std::string;
36using std::map;
37
38namespace android
39{
40namespace audio_policy
41{
42template <>
43StrategyCollection &Engine::getCollection<routing_strategy>()
44{
45    return mStrategyCollection;
46}
47template <>
48StreamCollection &Engine::getCollection<audio_stream_type_t>()
49{
50    return mStreamCollection;
51}
52template <>
53UsageCollection &Engine::getCollection<audio_usage_t>()
54{
55    return mUsageCollection;
56}
57template <>
58InputSourceCollection &Engine::getCollection<audio_source_t>()
59{
60    return mInputSourceCollection;
61}
62
63template <>
64const StrategyCollection &Engine::getCollection<routing_strategy>() const
65{
66    return mStrategyCollection;
67}
68template <>
69const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
70{
71    return mStreamCollection;
72}
73template <>
74const UsageCollection &Engine::getCollection<audio_usage_t>() const
75{
76    return mUsageCollection;
77}
78template <>
79const InputSourceCollection &Engine::getCollection<audio_source_t>() const
80{
81    return mInputSourceCollection;
82}
83
84Engine::Engine()
85    : mManagerInterface(this),
86      mPluginInterface(this),
87      mPolicyParameterMgr(new ParameterManagerWrapper()),
88      mApmObserver(NULL)
89{
90}
91
92Engine::~Engine()
93{
94    mStrategyCollection.clear();
95    mStreamCollection.clear();
96    mInputSourceCollection.clear();
97    mUsageCollection.clear();
98}
99
100
101void Engine::setObserver(AudioPolicyManagerObserver *observer)
102{
103    ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
104    mApmObserver = observer;
105}
106
107status_t Engine::initCheck()
108{
109    if (mPolicyParameterMgr == NULL || mPolicyParameterMgr->start() != NO_ERROR) {
110        ALOGE("%s: could not start Policy PFW", __FUNCTION__);
111        return NO_INIT;
112    }
113    return (mApmObserver != NULL)? NO_ERROR : NO_INIT;
114}
115
116template <typename Key>
117Element<Key> *Engine::getFromCollection(const Key &key) const
118{
119    const Collection<Key> collection = getCollection<Key>();
120    return collection.get(key);
121}
122
123template <typename Key>
124status_t Engine::add(const std::string &name, const Key &key)
125{
126    Collection<Key> &collection = getCollection<Key>();
127    return collection.add(name, key);
128}
129
130template <typename Property, typename Key>
131Property Engine::getPropertyForKey(Key key) const
132{
133    Element<Key> *element = getFromCollection<Key>(key);
134    if (element == NULL) {
135        ALOGE("%s: Element not found within collection", __FUNCTION__);
136        return static_cast<Property>(0);
137    }
138    return element->template get<Property>();
139}
140
141routing_strategy Engine::ManagerInterfaceImpl::getStrategyForUsage(audio_usage_t usage)
142{
143    return mPolicyEngine->getPropertyForKey<routing_strategy, audio_usage_t>(usage);
144}
145
146audio_devices_t Engine::ManagerInterfaceImpl::getDeviceForStrategy(routing_strategy strategy) const
147{
148    const SwAudioOutputCollection &outputs = mPolicyEngine->mApmObserver->getOutputs();
149
150    /** This is the only case handled programmatically because the PFW is unable to know the
151     * activity of streams.
152     *
153     * -While media is playing on a remote device, use the the sonification behavior.
154     * Note that we test this usecase before testing if media is playing because
155     * the isStreamActive() method only informs about the activity of a stream, not
156     * if it's for local playback. Note also that we use the same delay between both tests
157     *
158     * -When media is not playing anymore, fall back on the sonification behavior
159     */
160    if (strategy == STRATEGY_SONIFICATION_RESPECTFUL &&
161            !is_state_in_call(getPhoneState()) &&
162            !outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
163                                    SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY) &&
164            outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
165        return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(STRATEGY_MEDIA);
166    }
167    if (strategy == STRATEGY_ACCESSIBILITY &&
168        (outputs.isStreamActive(AUDIO_STREAM_RING) || outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
169            // do not route accessibility prompts to a digital output currently configured with a
170            // compressed format as they would likely not be mixed and dropped.
171            // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
172        return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(
173                    STRATEGY_SONIFICATION);
174    }
175    return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
176}
177
178bool Engine::PluginInterfaceImpl::setVolumeProfileForStream(const audio_stream_type_t &stream,
179                                                            const audio_stream_type_t &profile)
180{
181    if (mPolicyEngine->setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream,
182                                                                                   profile)) {
183        mPolicyEngine->mApmObserver->getVolumeCurves().switchVolumeCurve(profile, stream);
184        return true;
185    }
186    return false;
187}
188
189
190template <typename Property, typename Key>
191bool Engine::setPropertyForKey(const Property &property, const Key &key)
192{
193    Element<Key> *element = getFromCollection<Key>(key);
194    if (element == NULL) {
195        ALOGE("%s: Element not found within collection", __FUNCTION__);
196        return BAD_VALUE;
197    }
198    return element->template set<Property>(property) == NO_ERROR;
199}
200
201status_t Engine::setPhoneState(audio_mode_t mode)
202{
203    return mPolicyParameterMgr->setPhoneState(mode);
204}
205
206audio_mode_t Engine::getPhoneState() const
207{
208    return mPolicyParameterMgr->getPhoneState();
209}
210
211status_t Engine::setForceUse(audio_policy_force_use_t usage,
212                                      audio_policy_forced_cfg_t config)
213{
214    return mPolicyParameterMgr->setForceUse(usage, config);
215}
216
217audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
218{
219    return mPolicyParameterMgr->getForceUse(usage);
220}
221
222status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
223                                          audio_policy_dev_state_t /*state*/)
224{
225    if (audio_is_output_device(devDesc->type())) {
226        return mPolicyParameterMgr->setAvailableOutputDevices(
227                    mApmObserver->getAvailableOutputDevices().types());
228    } else if (audio_is_input_device(devDesc->type())) {
229        return mPolicyParameterMgr->setAvailableInputDevices(
230                    mApmObserver->getAvailableInputDevices().types());
231    }
232    return BAD_TYPE;
233}
234
235template <>
236AudioPolicyManagerInterface *Engine::queryInterface()
237{
238    return &mManagerInterface;
239}
240
241template <>
242AudioPolicyPluginInterface *Engine::queryInterface()
243{
244    return &mPluginInterface;
245}
246
247} // namespace audio_policy
248} // namespace android
249
250
251