/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* AndroidEffectSend implementation */

#include "sles_allinclusive.h"


static SLresult IAndroidEffectSend_EnableEffectSend(SLAndroidEffectSendItf self,
    SLInterfaceID effectImplementationId, SLboolean enable, SLmillibel initialLevel)
{
    SL_ENTER_INTERFACE

    if (!((SL_MILLIBEL_MIN <= initialLevel) && (initialLevel <= 0))) {
        result = SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
        interface_lock_exclusive(this);
        // is SLAndroidEffectSendItf on an AudioPlayer?
        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
                (CAudioPlayer *) this->mThis : NULL;
        if (NULL == ap) {
            SL_LOGE("invalid interface: not attached to an AudioPlayer");
            result = SL_RESULT_PARAMETER_INVALID;
        } else {
            // does this AudioPlayer have an OutputMix?
            if (NULL == ap->mOutputMix) {
                SL_LOGE("invalid interface: AudioPlayer doesn't have an OutputMix");
                result = SL_RESULT_PARAMETER_INVALID;
            } else {
#if !defined(ANDROID) || defined(USE_BACKPORT)
                result = SL_RESULT_SUCCESS;
#else
                result = android_fxSend_attachToAux(ap, effectImplementationId, enable,
                        initialLevel);
#endif
                if (SL_RESULT_SUCCESS == result) {
                    // there currently is support for only one send bus, so there is a single send
                    // level and a single enable flag
                    this->mSendLevel = initialLevel;
                    this->mEnabled = enable;
                }
            }
        }
        interface_unlock_exclusive(this);
    }

    SL_LEAVE_INTERFACE
}


static SLresult IAndroidEffectSend_IsEnabled(SLAndroidEffectSendItf self,
    SLInterfaceID effectImplementationId, SLboolean *pEnable)
{
    SL_ENTER_INTERFACE

    if (NULL == pEnable) {
        result = SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
        interface_lock_shared(this);
        // there currently is support for only one send bus, so there is a single enable flag
        SLboolean enable = this->mEnabled;
        interface_unlock_shared(this);
        *pEnable = enable;
        result = SL_RESULT_SUCCESS;
    }

    SL_LEAVE_INTERFACE
}


static SLresult IAndroidEffectSend_SetDirectLevel(SLAndroidEffectSendItf self,
        SLmillibel directLevel)
{
    SL_ENTER_INTERFACE

     if (!((SL_MILLIBEL_MIN <= directLevel) && (directLevel <= 0))) {
         result = SL_RESULT_PARAMETER_INVALID;
     } else {
         IAndroidEffectSend *this = (IAndroidEffectSend *) self;
         interface_lock_exclusive(this);
         CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
                 (CAudioPlayer *) this->mThis : NULL;
         if (NULL != ap) {
             SLmillibel oldDirectLevel = ap->mDirectLevel;
             if (oldDirectLevel != directLevel) {
                 ap->mDirectLevel = directLevel;
 #if defined(ANDROID)
                 ap->mAmplFromDirectLevel = sles_to_android_amplification(directLevel);
                 interface_unlock_exclusive_attributes(this, ATTR_GAIN);
 #endif
             } else {
                 interface_unlock_exclusive(this);
             }
             result = SL_RESULT_SUCCESS;
         } else {
             interface_unlock_exclusive(this);
             SL_LOGE("invalid interface: not attached to an AudioPlayer");
             result = SL_RESULT_PARAMETER_INVALID;
         }
     }

     SL_LEAVE_INTERFACE
}


static SLresult IAndroidEffectSend_GetDirectLevel(SLAndroidEffectSendItf self,
        SLmillibel *pDirectLevel)
{
    SL_ENTER_INTERFACE

    if (NULL == pDirectLevel) {
        result = SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
        interface_lock_peek(this);
        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
                (CAudioPlayer *) this->mThis : NULL;
        if (NULL != ap) {
            *pDirectLevel = ap->mDirectLevel;
            result = SL_RESULT_SUCCESS;
        } else {
            SL_LOGE("invalid interface: not attached to an AudioPlayer");
            result = SL_RESULT_PARAMETER_INVALID;
        }
        interface_unlock_exclusive(this);
    }

    SL_LEAVE_INTERFACE
}


static SLresult IAndroidEffectSend_SetSendLevel(SLAndroidEffectSendItf self,
        SLInterfaceID effectImplementationId, SLmillibel sendLevel)
{
    SL_ENTER_INTERFACE

    if (!((SL_MILLIBEL_MIN <= sendLevel) && (sendLevel <= 0))) {
        result = SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
         interface_lock_exclusive(this);
         // is SLAndroidEffectSendItf on an AudioPlayer?
         CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
                 (CAudioPlayer *) this->mThis : NULL;
         if (NULL == ap) {
             SL_LOGE("invalid interface: not attached to an AudioPlayer");
             result = SL_RESULT_PARAMETER_INVALID;
         } else {
             // does this AudioPlayer have an OutputMix?
             if (NULL == ap->mOutputMix) {
                 SL_LOGE("invalid interface: AudioPlayer doesn't have an OutputMix");
                 result = SL_RESULT_PARAMETER_INVALID;
             } else {
 #if !defined(ANDROID) || defined(USE_BACKPORT)
                 result = SL_RESULT_SUCCESS;
 #else
                 if (android_genericFx_hasEffect(&ap->mOutputMix->mAndroidEffect,
                         effectImplementationId)) {
                     result = android_fxSend_setSendLevel(ap, sendLevel);
                 } else {
                     SL_LOGE("trying to send to an effect not on this AudioPlayer's OutputMix");
                     result = SL_RESULT_PARAMETER_INVALID;
                 }
 #endif
                 if (SL_RESULT_SUCCESS == result) {
                     // there currently is support for only one send bus, so there is a single send
                     // level
                     this->mSendLevel = sendLevel;
                 }
             }
         }
         interface_unlock_exclusive(this);
    }

    SL_LEAVE_INTERFACE
}


static SLresult IAndroidEffectSend_GetSendLevel(SLAndroidEffectSendItf self,
        SLInterfaceID effectImplementationId, SLmillibel *pSendLevel)
{
    SL_ENTER_INTERFACE

    if (NULL == pSendLevel) {
        result = SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidEffectSend *this = (IAndroidEffectSend *) self;
        interface_lock_exclusive(this);
        // is SLAndroidEffectSendItf on an AudioPlayer?
        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
                (CAudioPlayer *) this->mThis : NULL;
        if (NULL == ap) {
            SL_LOGE("invalid interface: not attached to an AudioPlayer");
            result = SL_RESULT_PARAMETER_INVALID;
        } else {
            // does this AudioPlayer have an OutputMix?
            if (NULL == ap->mOutputMix) {
                SL_LOGE("invalid interface: AudioPlayer doesn't have an OutputMix");
                result = SL_RESULT_PARAMETER_INVALID;
            } else {
#if !defined(ANDROID) || defined(USE_BACKPORT)
                result = SL_RESULT_SUCCESS;
#else
                if (android_genericFx_hasEffect(&ap->mOutputMix->mAndroidEffect,
                        effectImplementationId)) {
                    result = SL_RESULT_SUCCESS;
                } else {
                    SL_LOGE("trying to retrieve send level on an effect not on this AudioPlayer's \
OutputMix");
                    result = SL_RESULT_PARAMETER_INVALID;
                }
#endif
                if (SL_RESULT_SUCCESS == result) {
                    // there currently is support for only one send bus, so there is a single send
                    // level
                    *pSendLevel = this->mSendLevel;
                }
            }
        }
        interface_unlock_exclusive(this);
    }

    SL_LEAVE_INTERFACE
}


static const struct SLAndroidEffectSendItf_ IAndroidEffectSend_Itf = {
    IAndroidEffectSend_EnableEffectSend,
    IAndroidEffectSend_IsEnabled,
    IAndroidEffectSend_SetDirectLevel,
    IAndroidEffectSend_GetDirectLevel,
    IAndroidEffectSend_SetSendLevel,
    IAndroidEffectSend_GetSendLevel
};

void IAndroidEffectSend_init(void *self)
{
    IAndroidEffectSend *this = (IAndroidEffectSend *) self;
    this->mItf = &IAndroidEffectSend_Itf;
    this->mEnabled =  SL_BOOLEAN_FALSE;
    this->mSendLevel = SL_MILLIBEL_MIN;
}
