Home | History | Annotate | Download | only in libopensles
      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 
     39 static 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  */
     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 
    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         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 
    160 static 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 
    186 static 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 
    221 static 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 
    246 static 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 
    281 static 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 
    306 static 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 
    315 void 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