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
24static 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
39static 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 */
97static 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
111static 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
162static 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
188static 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
225static 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
250static 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
287static 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
312static 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
321void 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