1 /*
2 * Copyright (C) 2010 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 /* EffectSend implementation */
18
19 #include "sles_allinclusive.h"
20
21
22 /** \brief Maps AUX index to OutputMix interface index */
23
24 static const unsigned char AUX_to_MPH[AUX_MAX] = {
25 MPH_ENVIRONMENTALREVERB,
26 MPH_PRESETREVERB
27 };
28
29
30 /** \brief This is a private function that validates the effect interface specified by the
31 * application when it calls EnableEffectSend, IsEnabled, SetSendLevel, or GetSendLevel.
32 * For the interface to be valid, it has to satisfy these requirements:
33 * - object is an audio player (MIDI player is not supported yet)
34 * - audio sink is an output mix
35 * - interface was exposed at object creation time or by DynamicInterface::AddInterface
36 * - interface was "gotten" with Object::GetInterface
37 */
38
getEnableLevel(IEffectSend * thiz,const void * pAuxEffect)39 static struct EnableLevel *getEnableLevel(IEffectSend *thiz, const void *pAuxEffect)
40 {
41 // Make sure this effect send is on an audio player, not a MIDI player
42 CAudioPlayer *audioPlayer = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
43 (CAudioPlayer *) thiz->mThis : NULL;
44 if (NULL == audioPlayer) {
45 return NULL;
46 }
47 // Get the output mix for this player
48 COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
49 unsigned aux;
50 if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) {
51 aux = AUX_ENVIRONMENTALREVERB;
52 } else if (pAuxEffect == &outputMix->mPresetReverb.mItf) {
53 aux = AUX_PRESETREVERB;
54 } else {
55 SL_LOGE("EffectSend on unknown aux effect %p", pAuxEffect);
56 return NULL;
57 }
58 assert(aux < AUX_MAX);
59 // Validate that the application has a valid interface for the effect. The interface must have
60 // been exposed at object creation time or by DynamicInterface::AddInterface, and it also must
61 // have been "gotten" with Object::GetInterface.
62 unsigned MPH = AUX_to_MPH[aux];
63 int index = MPH_to_OutputMix[MPH];
64 if (0 > index) {
65 SL_LOGE("EffectSend aux=%u MPH=%u", aux, MPH);
66 return NULL;
67 }
68 unsigned mask = 1 << index;
69 object_lock_shared(&outputMix->mObject);
70 SLuint32 state = outputMix->mObject.mInterfaceStates[index];
71 mask &= outputMix->mObject.mGottenMask;
72 object_unlock_shared(&outputMix->mObject);
73 switch (state) {
74 case INTERFACE_EXPOSED:
75 case INTERFACE_ADDED:
76 case INTERFACE_SUSPENDED:
77 case INTERFACE_SUSPENDING:
78 case INTERFACE_RESUMING_1:
79 case INTERFACE_RESUMING_2:
80 if (mask) {
81 return &thiz->mEnableLevels[aux];
82 }
83 SL_LOGE("EffectSend no GetInterface yet");
84 break;
85 default:
86 SL_LOGE("EffectSend invalid interface state %u", state);
87 break;
88 }
89 return NULL;
90 }
91
92 #if defined(ANDROID)
93 /** \brief This is a private function that translates an Android effect framework status code
94 * to the SL ES result code used in the EnableEffectSend() function of the SLEffectSendItf
95 * interface.
96 */
translateEnableFxSendError(android::status_t status)97 static SLresult translateEnableFxSendError(android::status_t status) {
98 switch (status) {
99 case android::NO_ERROR:
100 return SL_RESULT_SUCCESS;
101 case android::INVALID_OPERATION:
102 case android::BAD_VALUE:
103 default:
104 SL_LOGE("EffectSend status %u", status);
105 return SL_RESULT_RESOURCE_ERROR;
106 }
107 }
108 #endif
109
110
IEffectSend_EnableEffectSend(SLEffectSendItf self,const void * pAuxEffect,SLboolean enable,SLmillibel initialLevel)111 static SLresult IEffectSend_EnableEffectSend(SLEffectSendItf self,
112 const void *pAuxEffect, SLboolean enable, SLmillibel initialLevel)
113 {
114 SL_ENTER_INTERFACE
115
116 //if (!((SL_MILLIBEL_MIN <= initialLevel) && (initialLevel <= 0))) {
117 // comparison (SL_MILLIBEL_MIN <= initialLevel) is always true due to range of SLmillibel
118 if (!(initialLevel <= 0)) {
119 result = SL_RESULT_PARAMETER_INVALID;
120 } else {
121 IEffectSend *thiz = (IEffectSend *) self;
122 struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
123 if (NULL == enableLevel) {
124 result = SL_RESULT_PARAMETER_INVALID;
125 } else {
126 interface_lock_exclusive(thiz);
127 enableLevel->mEnable = SL_BOOLEAN_FALSE != enable; // normalize
128 enableLevel->mSendLevel = initialLevel;
129 #if !defined(ANDROID)
130 result = SL_RESULT_SUCCESS;
131 #else
132 // TODO do not repeat querying of CAudioPlayer, done inside getEnableLevel()
133 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
134 (CAudioPlayer *) thiz->mThis : NULL;
135 // note that if this was a MIDI player, getEnableLevel would have returned NULL
136 assert(NULL != ap);
137 // check which effect the send is attached to, attach and set level
138 COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap);
139 // the initial send level set here is the total energy on the aux bus,
140 // so it must take into account the player volume level
141 if (pAuxEffect == &outputMix->mPresetReverb.mItf) {
142 result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable,
143 outputMix->mPresetReverb.mPresetReverbEffect,
144 initialLevel + ap->mVolume.mLevel));
145 } else if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) {
146 result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable,
147 outputMix->mEnvironmentalReverb.mEnvironmentalReverbEffect,
148 initialLevel + ap->mVolume.mLevel));
149 } else {
150 SL_LOGE("EffectSend unknown aux effect %p", pAuxEffect);
151 result = SL_RESULT_PARAMETER_INVALID;
152 }
153 #endif
154 interface_unlock_exclusive(thiz);
155 }
156 }
157
158 SL_LEAVE_INTERFACE
159 }
160
161
IEffectSend_IsEnabled(SLEffectSendItf self,const void * pAuxEffect,SLboolean * pEnable)162 static SLresult IEffectSend_IsEnabled(SLEffectSendItf self,
163 const void *pAuxEffect, SLboolean *pEnable)
164 {
165 SL_ENTER_INTERFACE
166
167 if (NULL == pEnable) {
168 result = SL_RESULT_PARAMETER_INVALID;
169 } else {
170 IEffectSend *thiz = (IEffectSend *) self;
171 struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
172 if (NULL == enableLevel) {
173 *pEnable = SL_BOOLEAN_FALSE;
174 result = SL_RESULT_PARAMETER_INVALID;
175 } else {
176 interface_lock_shared(thiz);
177 SLboolean enable = enableLevel->mEnable;
178 interface_unlock_shared(thiz);
179 *pEnable = enable;
180 result = SL_RESULT_SUCCESS;
181 }
182 }
183
184 SL_LEAVE_INTERFACE
185 }
186
187
IEffectSend_SetDirectLevel(SLEffectSendItf self,SLmillibel directLevel)188 static SLresult IEffectSend_SetDirectLevel(SLEffectSendItf self, SLmillibel directLevel)
189 {
190 SL_ENTER_INTERFACE
191
192 //if (!((SL_MILLIBEL_MIN <= directLevel) && (directLevel <= 0))) {
193 // comparison (SL_MILLIBEL_MIN <= directLevel) is always true due to range of SLmillibel
194 if (!(directLevel <= 0)) {
195 result = SL_RESULT_PARAMETER_INVALID;
196 } else {
197 IEffectSend *thiz = (IEffectSend *) self;
198 interface_lock_exclusive(thiz);
199 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
200 (CAudioPlayer *) thiz->mThis : NULL;
201 if (NULL != ap) {
202 SLmillibel oldDirectLevel = ap->mDirectLevel;
203 if (oldDirectLevel != directLevel) {
204 ap->mDirectLevel = directLevel;
205 #if defined(ANDROID)
206 ap->mAmplFromDirectLevel = sles_to_android_amplification(directLevel);
207 interface_unlock_exclusive_attributes(thiz, ATTR_GAIN);
208 #else
209 interface_unlock_exclusive(thiz);
210 #endif
211 } else {
212 interface_unlock_exclusive(thiz);
213 }
214 } else {
215 // MIDI player is silently not supported
216 interface_unlock_exclusive(thiz);
217 }
218 result = SL_RESULT_SUCCESS;
219 }
220
221 SL_LEAVE_INTERFACE
222 }
223
224
IEffectSend_GetDirectLevel(SLEffectSendItf self,SLmillibel * pDirectLevel)225 static SLresult IEffectSend_GetDirectLevel(SLEffectSendItf self, SLmillibel *pDirectLevel)
226 {
227 SL_ENTER_INTERFACE
228
229 if (NULL == pDirectLevel) {
230 result = SL_RESULT_PARAMETER_INVALID;
231 } else {
232 IEffectSend *thiz = (IEffectSend *) self;
233 interface_lock_shared(thiz);
234 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
235 (CAudioPlayer *) thiz->mThis : NULL;
236 if (NULL != ap) {
237 *pDirectLevel = ap->mDirectLevel;
238 } else {
239 // MIDI player is silently not supported
240 *pDirectLevel = 0;
241 }
242 interface_unlock_shared(thiz);
243 result = SL_RESULT_SUCCESS;
244 }
245
246 SL_LEAVE_INTERFACE
247 }
248
249
IEffectSend_SetSendLevel(SLEffectSendItf self,const void * pAuxEffect,SLmillibel sendLevel)250 static SLresult IEffectSend_SetSendLevel(SLEffectSendItf self, const void *pAuxEffect,
251 SLmillibel sendLevel)
252 {
253 SL_ENTER_INTERFACE
254
255 //if (!((SL_MILLIBEL_MIN <= sendLevel) && (sendLevel <= 0))) {
256 // comparison (SL_MILLIBEL_MIN <= sendLevel) is always true due to range of SLmillibel
257 if (!(sendLevel <= 0)) {
258 result = SL_RESULT_PARAMETER_INVALID;
259 } else {
260 IEffectSend *thiz = (IEffectSend *) self;
261 struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
262 if (NULL == enableLevel) {
263 result = SL_RESULT_PARAMETER_INVALID;
264 } else {
265 result = SL_RESULT_SUCCESS;
266 // EnableEffectSend is exclusive, so this has to be also
267 interface_lock_exclusive(thiz);
268 enableLevel->mSendLevel = sendLevel;
269 #if defined(ANDROID)
270 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
271 (CAudioPlayer *) thiz->mThis : NULL;
272 if (NULL != ap) {
273 // the send level set here is the total energy on the aux bus, so it must take
274 // into account the player volume level
275 result = android_fxSend_setSendLevel(ap, sendLevel + ap->mVolume.mLevel);
276 }
277 #endif
278 interface_unlock_exclusive(thiz);
279
280 }
281 }
282
283 SL_LEAVE_INTERFACE
284 }
285
286
IEffectSend_GetSendLevel(SLEffectSendItf self,const void * pAuxEffect,SLmillibel * pSendLevel)287 static SLresult IEffectSend_GetSendLevel(SLEffectSendItf self, const void *pAuxEffect,
288 SLmillibel *pSendLevel)
289 {
290 SL_ENTER_INTERFACE
291
292 if (NULL == pSendLevel) {
293 result = SL_RESULT_PARAMETER_INVALID;
294 } else {
295 IEffectSend *thiz = (IEffectSend *) self;
296 struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
297 if (NULL == enableLevel) {
298 result = SL_RESULT_PARAMETER_INVALID;
299 } else {
300 interface_lock_shared(thiz);
301 SLmillibel sendLevel = enableLevel->mSendLevel;
302 interface_unlock_shared(thiz);
303 *pSendLevel = sendLevel;
304 result = SL_RESULT_SUCCESS;
305 }
306 }
307
308 SL_LEAVE_INTERFACE
309 }
310
311
312 static const struct SLEffectSendItf_ IEffectSend_Itf = {
313 IEffectSend_EnableEffectSend,
314 IEffectSend_IsEnabled,
315 IEffectSend_SetDirectLevel,
316 IEffectSend_GetDirectLevel,
317 IEffectSend_SetSendLevel,
318 IEffectSend_GetSendLevel
319 };
320
IEffectSend_init(void * self)321 void IEffectSend_init(void *self)
322 {
323 IEffectSend *thiz = (IEffectSend *) self;
324 thiz->mItf = &IEffectSend_Itf;
325 struct EnableLevel *enableLevel = thiz->mEnableLevels;
326 unsigned aux;
327 for (aux = 0; aux < AUX_MAX; ++aux, ++enableLevel) {
328 enableLevel->mEnable = SL_BOOLEAN_FALSE;
329 enableLevel->mSendLevel = SL_MILLIBEL_MIN;
330 }
331 }
332