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