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 
35 using std::string;
36 using std::map;
37 
38 namespace android
39 {
40 namespace audio_policy
41 {
42 template <>
getCollection()43 StrategyCollection &Engine::getCollection<routing_strategy>()
44 {
45     return mStrategyCollection;
46 }
47 template <>
getCollection()48 StreamCollection &Engine::getCollection<audio_stream_type_t>()
49 {
50     return mStreamCollection;
51 }
52 template <>
getCollection()53 UsageCollection &Engine::getCollection<audio_usage_t>()
54 {
55     return mUsageCollection;
56 }
57 template <>
getCollection()58 InputSourceCollection &Engine::getCollection<audio_source_t>()
59 {
60     return mInputSourceCollection;
61 }
62 
63 template <>
getCollection() const64 const StrategyCollection &Engine::getCollection<routing_strategy>() const
65 {
66     return mStrategyCollection;
67 }
68 template <>
getCollection() const69 const StreamCollection &Engine::getCollection<audio_stream_type_t>() const
70 {
71     return mStreamCollection;
72 }
73 template <>
getCollection() const74 const UsageCollection &Engine::getCollection<audio_usage_t>() const
75 {
76     return mUsageCollection;
77 }
78 template <>
getCollection() const79 const InputSourceCollection &Engine::getCollection<audio_source_t>() const
80 {
81     return mInputSourceCollection;
82 }
83 
Engine()84 Engine::Engine()
85     : mManagerInterface(this),
86       mPluginInterface(this),
87       mPolicyParameterMgr(new ParameterManagerWrapper()),
88       mApmObserver(NULL)
89 {
90 }
91 
~Engine()92 Engine::~Engine()
93 {
94     mStrategyCollection.clear();
95     mStreamCollection.clear();
96     mInputSourceCollection.clear();
97     mUsageCollection.clear();
98 }
99 
100 
setObserver(AudioPolicyManagerObserver * observer)101 void Engine::setObserver(AudioPolicyManagerObserver *observer)
102 {
103     ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
104     mApmObserver = observer;
105 }
106 
initCheck()107 status_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 
116 template <typename Key>
getFromCollection(const Key & key) const117 Element<Key> *Engine::getFromCollection(const Key &key) const
118 {
119     const Collection<Key> collection = getCollection<Key>();
120     return collection.get(key);
121 }
122 
123 template <typename Key>
add(const std::string & name,const Key & key)124 status_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 
130 template <typename Property, typename Key>
getPropertyForKey(Key key) const131 Property 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 
getStrategyForUsage(audio_usage_t usage)141 routing_strategy Engine::ManagerInterfaceImpl::getStrategyForUsage(audio_usage_t usage)
142 {
143     return mPolicyEngine->getPropertyForKey<routing_strategy, audio_usage_t>(usage);
144 }
145 
getDeviceForStrategy(routing_strategy strategy) const146 audio_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 
setVolumeProfileForStream(const audio_stream_type_t & stream,const audio_stream_type_t & profile)178 bool 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 
190 template <typename Property, typename Key>
setPropertyForKey(const Property & property,const Key & key)191 bool 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 
setPhoneState(audio_mode_t mode)201 status_t Engine::setPhoneState(audio_mode_t mode)
202 {
203     return mPolicyParameterMgr->setPhoneState(mode);
204 }
205 
getPhoneState() const206 audio_mode_t Engine::getPhoneState() const
207 {
208     return mPolicyParameterMgr->getPhoneState();
209 }
210 
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)211 status_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 
getForceUse(audio_policy_force_use_t usage) const217 audio_policy_forced_cfg_t Engine::getForceUse(audio_policy_force_use_t usage) const
218 {
219     return mPolicyParameterMgr->getForceUse(usage);
220 }
221 
setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,audio_policy_dev_state_t)222 status_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 
235 template <>
queryInterface()236 AudioPolicyManagerInterface *Engine::queryInterface()
237 {
238     return &mManagerInterface;
239 }
240 
241 template <>
queryInterface()242 AudioPolicyPluginInterface *Engine::queryInterface()
243 {
244     return &mPluginInterface;
245 }
246 
247 } // namespace audio_policy
248 } // namespace android
249 
250 
251