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/* AndroidEffectSend implementation */
18
19#include "sles_allinclusive.h"
20
21
22static SLresult IAndroidEffectSend_EnableEffectSend(SLAndroidEffectSendItf self,
23    SLInterfaceID effectImplementationId, SLboolean enable, SLmillibel initialLevel)
24{
25    SL_ENTER_INTERFACE
26
27    if (!((SL_MILLIBEL_MIN <= initialLevel) && (initialLevel <= 0))) {
28        result = SL_RESULT_PARAMETER_INVALID;
29    } else {
30        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
31        interface_lock_exclusive(this);
32        // is SLAndroidEffectSendItf on an AudioPlayer?
33        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
34                (CAudioPlayer *) this->mThis : NULL;
35        if (NULL == ap) {
36            SL_LOGE("invalid interface: not attached to an AudioPlayer");
37            result = SL_RESULT_PARAMETER_INVALID;
38        } else {
39            COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap);
40#ifdef USE_BACKPORT
41            result = SL_RESULT_SUCCESS;
42#else
43            // the initial send level set here is the total energy on the aux bus,
44            //  so it must take into account the player volume level
45            result = android_fxSend_attachToAux(ap, effectImplementationId, enable,
46                    initialLevel + ap->mVolume.mLevel);
47#endif
48            if (SL_RESULT_SUCCESS == result) {
49                // there currently is support for only one send bus, so there is a single send
50                // level and a single enable flag
51                this->mSendLevel = initialLevel;
52                this->mEnabled = enable;
53            }
54        }
55        interface_unlock_exclusive(this);
56    }
57
58    SL_LEAVE_INTERFACE
59}
60
61
62static SLresult IAndroidEffectSend_IsEnabled(SLAndroidEffectSendItf self,
63    SLInterfaceID effectImplementationId, SLboolean *pEnable)
64{
65    SL_ENTER_INTERFACE
66
67    if (NULL == pEnable) {
68        result = SL_RESULT_PARAMETER_INVALID;
69    } else {
70        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
71        interface_lock_shared(this);
72        // there currently is support for only one send bus, so there is a single enable flag
73        SLboolean enable = this->mEnabled;
74        interface_unlock_shared(this);
75        *pEnable = enable;
76        result = SL_RESULT_SUCCESS;
77    }
78
79    SL_LEAVE_INTERFACE
80}
81
82
83static SLresult IAndroidEffectSend_SetDirectLevel(SLAndroidEffectSendItf self,
84        SLmillibel directLevel)
85{
86    SL_ENTER_INTERFACE
87
88     if (!((SL_MILLIBEL_MIN <= directLevel) && (directLevel <= 0))) {
89         result = SL_RESULT_PARAMETER_INVALID;
90     } else {
91         IAndroidEffectSend *this = (IAndroidEffectSend *) self;
92         interface_lock_exclusive(this);
93         CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
94                 (CAudioPlayer *) this->mThis : NULL;
95         if (NULL != ap) {
96             SLmillibel oldDirectLevel = ap->mDirectLevel;
97             if (oldDirectLevel != directLevel) {
98                 ap->mDirectLevel = directLevel;
99                 ap->mAmplFromDirectLevel = sles_to_android_amplification(directLevel);
100                 interface_unlock_exclusive_attributes(this, ATTR_GAIN);
101             } else {
102                 interface_unlock_exclusive(this);
103             }
104             result = SL_RESULT_SUCCESS;
105         } else {
106             interface_unlock_exclusive(this);
107             SL_LOGE("invalid interface: not attached to an AudioPlayer");
108             result = SL_RESULT_PARAMETER_INVALID;
109         }
110     }
111
112     SL_LEAVE_INTERFACE
113}
114
115
116static SLresult IAndroidEffectSend_GetDirectLevel(SLAndroidEffectSendItf self,
117        SLmillibel *pDirectLevel)
118{
119    SL_ENTER_INTERFACE
120
121    if (NULL == pDirectLevel) {
122        result = SL_RESULT_PARAMETER_INVALID;
123    } else {
124        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
125        interface_lock_peek(this);
126        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
127                (CAudioPlayer *) this->mThis : NULL;
128        if (NULL != ap) {
129            *pDirectLevel = ap->mDirectLevel;
130            result = SL_RESULT_SUCCESS;
131        } else {
132            SL_LOGE("invalid interface: not attached to an AudioPlayer");
133            result = SL_RESULT_PARAMETER_INVALID;
134        }
135        interface_unlock_peek(this);
136    }
137
138    SL_LEAVE_INTERFACE
139}
140
141
142static SLresult IAndroidEffectSend_SetSendLevel(SLAndroidEffectSendItf self,
143        SLInterfaceID effectImplementationId, SLmillibel sendLevel)
144{
145    SL_ENTER_INTERFACE
146
147    if (!((SL_MILLIBEL_MIN <= sendLevel) && (sendLevel <= 0))) {
148        result = SL_RESULT_PARAMETER_INVALID;
149    } else {
150        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
151        interface_lock_exclusive(this);
152        // is SLAndroidEffectSendItf on an AudioPlayer?
153        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
154                 (CAudioPlayer *) this->mThis : NULL;
155        if (NULL == ap) {
156            SL_LOGE("invalid interface: not attached to an AudioPlayer");
157            result = SL_RESULT_PARAMETER_INVALID;
158        } else {
159            COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap);
160#ifdef USE_BACKPORT
161            result = SL_RESULT_SUCCESS;
162#else
163            if (android_genericFx_hasEffect(&outputMix->mAndroidEffect, effectImplementationId)) {
164                // the send level set here is the total energy on the aux bus, so it must take
165                // into account the player volume level
166                result = android_fxSend_setSendLevel(ap, sendLevel + ap->mVolume.mLevel);
167            } else {
168                 SL_LOGE("trying to send to an effect not on this AudioPlayer's OutputMix");
169                 result = SL_RESULT_PARAMETER_INVALID;
170            }
171#endif
172            if (SL_RESULT_SUCCESS == result) {
173                // there currently is support for only one send bus, so there is a single send
174                // level
175                this->mSendLevel = sendLevel;
176            }
177        }
178        interface_unlock_exclusive(this);
179    }
180
181    SL_LEAVE_INTERFACE
182}
183
184
185static SLresult IAndroidEffectSend_GetSendLevel(SLAndroidEffectSendItf self,
186        SLInterfaceID effectImplementationId, SLmillibel *pSendLevel)
187{
188    SL_ENTER_INTERFACE
189
190    if (NULL == pSendLevel) {
191        result = SL_RESULT_PARAMETER_INVALID;
192    } else {
193        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
194        interface_lock_exclusive(this);
195        // is SLAndroidEffectSendItf on an AudioPlayer?
196        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
197                (CAudioPlayer *) this->mThis : NULL;
198        if (NULL == ap) {
199            SL_LOGE("invalid interface: not attached to an AudioPlayer");
200            result = SL_RESULT_PARAMETER_INVALID;
201        } else {
202            COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap);
203#ifdef USE_BACKPORT
204            result = SL_RESULT_SUCCESS;
205#else
206            if (android_genericFx_hasEffect(&outputMix->mAndroidEffect, effectImplementationId)) {
207                result = SL_RESULT_SUCCESS;
208            } else {
209                SL_LOGE("trying to retrieve send level on an effect not on this AudioPlayer's \
210OutputMix");
211                result = SL_RESULT_PARAMETER_INVALID;
212                }
213#endif
214            if (SL_RESULT_SUCCESS == result) {
215                // there currently is support for only one send bus, so there is a single send
216                // level
217                *pSendLevel = this->mSendLevel;
218            }
219        }
220        interface_unlock_exclusive(this);
221    }
222
223    SL_LEAVE_INTERFACE
224}
225
226
227static const struct SLAndroidEffectSendItf_ IAndroidEffectSend_Itf = {
228    IAndroidEffectSend_EnableEffectSend,
229    IAndroidEffectSend_IsEnabled,
230    IAndroidEffectSend_SetDirectLevel,
231    IAndroidEffectSend_GetDirectLevel,
232    IAndroidEffectSend_SetSendLevel,
233    IAndroidEffectSend_GetSendLevel
234};
235
236void IAndroidEffectSend_init(void *self)
237{
238    IAndroidEffectSend *this = (IAndroidEffectSend *) self;
239    this->mItf = &IAndroidEffectSend_Itf;
240    this->mEnabled =  SL_BOOLEAN_FALSE;
241    this->mSendLevel = SL_MILLIBEL_MIN;
242}
243