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