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 *this, 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(this)) ? 43 (CAudioPlayer *) this->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 &this->mEnableLevels[aux]; 82 } 83 SL_LOGE("EffectSend no GetInterface yet"); 84 break; 85 default: 86 SL_LOGE("EffectSend invalid interface state %lu", state); 87 break; 88 } 89 return NULL; 90} 91 92#if defined(ANDROID) && !defined(USE_BACKPORT) 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 result = SL_RESULT_PARAMETER_INVALID; 118 } else { 119 IEffectSend *this = (IEffectSend *) self; 120 struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect); 121 if (NULL == enableLevel) { 122 result = SL_RESULT_PARAMETER_INVALID; 123 } else { 124 interface_lock_exclusive(this); 125 enableLevel->mEnable = SL_BOOLEAN_FALSE != enable; // normalize 126 enableLevel->mSendLevel = initialLevel; 127#if !defined(ANDROID) || defined(USE_BACKPORT) 128 result = SL_RESULT_SUCCESS; 129#else 130 // TODO do not repeat querying of CAudioPlayer, done inside getEnableLevel() 131 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ? 132 (CAudioPlayer *) this->mThis : NULL; 133 // note that if this was a MIDI player, getEnableLevel would have returned NULL 134 assert(NULL != ap); 135 // check which effect the send is attached to, attach and set level 136 COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap); 137 // the initial send level set here is the total energy on the aux bus, 138 // so it must take into account the player volume level 139 if (pAuxEffect == &outputMix->mPresetReverb.mItf) { 140 result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable, 141 outputMix->mPresetReverb.mPresetReverbEffect, 142 initialLevel + ap->mVolume.mLevel)); 143 } else if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) { 144 result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable, 145 outputMix->mEnvironmentalReverb.mEnvironmentalReverbEffect, 146 initialLevel + ap->mVolume.mLevel)); 147 } else { 148 SL_LOGE("EffectSend unknown aux effect %p", pAuxEffect); 149 result = SL_RESULT_PARAMETER_INVALID; 150 } 151#endif 152 interface_unlock_exclusive(this); 153 } 154 } 155 156 SL_LEAVE_INTERFACE 157} 158 159 160static SLresult IEffectSend_IsEnabled(SLEffectSendItf self, 161 const void *pAuxEffect, SLboolean *pEnable) 162{ 163 SL_ENTER_INTERFACE 164 165 if (NULL == pEnable) { 166 result = SL_RESULT_PARAMETER_INVALID; 167 } else { 168 IEffectSend *this = (IEffectSend *) self; 169 struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect); 170 if (NULL == enableLevel) { 171 *pEnable = SL_BOOLEAN_FALSE; 172 result = SL_RESULT_PARAMETER_INVALID; 173 } else { 174 interface_lock_shared(this); 175 SLboolean enable = enableLevel->mEnable; 176 interface_unlock_shared(this); 177 *pEnable = enable; 178 result = SL_RESULT_SUCCESS; 179 } 180 } 181 182 SL_LEAVE_INTERFACE 183} 184 185 186static SLresult IEffectSend_SetDirectLevel(SLEffectSendItf self, SLmillibel directLevel) 187{ 188 SL_ENTER_INTERFACE 189 190 if (!((SL_MILLIBEL_MIN <= directLevel) && (directLevel <= 0))) { 191 result = SL_RESULT_PARAMETER_INVALID; 192 } else { 193 IEffectSend *this = (IEffectSend *) self; 194 interface_lock_exclusive(this); 195 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ? 196 (CAudioPlayer *) this->mThis : NULL; 197 if (NULL != ap) { 198 SLmillibel oldDirectLevel = ap->mDirectLevel; 199 if (oldDirectLevel != directLevel) { 200 ap->mDirectLevel = directLevel; 201#if defined(ANDROID) 202 ap->mAmplFromDirectLevel = sles_to_android_amplification(directLevel); 203 interface_unlock_exclusive_attributes(this, ATTR_GAIN); 204#else 205 interface_unlock_exclusive(this); 206#endif 207 } else { 208 interface_unlock_exclusive(this); 209 } 210 } else { 211 // MIDI player is silently not supported 212 interface_unlock_exclusive(this); 213 } 214 result = SL_RESULT_SUCCESS; 215 } 216 217 SL_LEAVE_INTERFACE 218} 219 220 221static SLresult IEffectSend_GetDirectLevel(SLEffectSendItf self, SLmillibel *pDirectLevel) 222{ 223 SL_ENTER_INTERFACE 224 225 if (NULL == pDirectLevel) { 226 result = SL_RESULT_PARAMETER_INVALID; 227 } else { 228 IEffectSend *this = (IEffectSend *) self; 229 interface_lock_shared(this); 230 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ? 231 (CAudioPlayer *) this->mThis : NULL; 232 if (NULL != ap) { 233 *pDirectLevel = ap->mDirectLevel; 234 } else { 235 // MIDI player is silently not supported 236 *pDirectLevel = 0; 237 } 238 interface_unlock_shared(this); 239 result = SL_RESULT_SUCCESS; 240 } 241 242 SL_LEAVE_INTERFACE 243} 244 245 246static SLresult IEffectSend_SetSendLevel(SLEffectSendItf self, const void *pAuxEffect, 247 SLmillibel sendLevel) 248{ 249 SL_ENTER_INTERFACE 250 251 if (!((SL_MILLIBEL_MIN <= sendLevel) && (sendLevel <= 0))) { 252 result = SL_RESULT_PARAMETER_INVALID; 253 } else { 254 IEffectSend *this = (IEffectSend *) self; 255 struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect); 256 if (NULL == enableLevel) { 257 result = SL_RESULT_PARAMETER_INVALID; 258 } else { 259 result = SL_RESULT_SUCCESS; 260 // EnableEffectSend is exclusive, so this has to be also 261 interface_lock_exclusive(this); 262 enableLevel->mSendLevel = sendLevel; 263#if defined(ANDROID) && !defined(USE_BACKPORT) 264 CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ? 265 (CAudioPlayer *) this->mThis : NULL; 266 if (NULL != ap) { 267 // the send level set here is the total energy on the aux bus, so it must take 268 // into account the player volume level 269 result = android_fxSend_setSendLevel(ap, sendLevel + ap->mVolume.mLevel); 270 } 271#endif 272 interface_unlock_exclusive(this); 273 274 } 275 } 276 277 SL_LEAVE_INTERFACE 278} 279 280 281static SLresult IEffectSend_GetSendLevel(SLEffectSendItf self, const void *pAuxEffect, 282 SLmillibel *pSendLevel) 283{ 284 SL_ENTER_INTERFACE 285 286 if (NULL == pSendLevel) { 287 result = SL_RESULT_PARAMETER_INVALID; 288 } else { 289 IEffectSend *this = (IEffectSend *) self; 290 struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect); 291 if (NULL == enableLevel) { 292 result = SL_RESULT_PARAMETER_INVALID; 293 } else { 294 interface_lock_shared(this); 295 SLmillibel sendLevel = enableLevel->mSendLevel; 296 interface_unlock_shared(this); 297 *pSendLevel = sendLevel; 298 result = SL_RESULT_SUCCESS; 299 } 300 } 301 302 SL_LEAVE_INTERFACE 303} 304 305 306static const struct SLEffectSendItf_ IEffectSend_Itf = { 307 IEffectSend_EnableEffectSend, 308 IEffectSend_IsEnabled, 309 IEffectSend_SetDirectLevel, 310 IEffectSend_GetDirectLevel, 311 IEffectSend_SetSendLevel, 312 IEffectSend_GetSendLevel 313}; 314 315void IEffectSend_init(void *self) 316{ 317 IEffectSend *this = (IEffectSend *) self; 318 this->mItf = &IEffectSend_Itf; 319 struct EnableLevel *enableLevel = this->mEnableLevels; 320 unsigned aux; 321 for (aux = 0; aux < AUX_MAX; ++aux, ++enableLevel) { 322 enableLevel->mEnable = SL_BOOLEAN_FALSE; 323 enableLevel->mSendLevel = SL_MILLIBEL_MIN; 324 } 325} 326