Home | History | Annotate | Download | only in itf
      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 *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  */
     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     // 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 
    162 static 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 
    188 static 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 
    225 static 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 
    250 static 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 
    287 static 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 
    312 static 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 
    321 void 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