OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / system / media / opensles / libopensles / IEffectSend.c
diff --git a/system/media/opensles/libopensles/IEffectSend.c b/system/media/opensles/libopensles/IEffectSend.c
new file mode 100644 (file)
index 0000000..b21495e
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+/* EffectSend implementation */
+
+#include "sles_allinclusive.h"
+
+
+/** \brief Maps AUX index to OutputMix interface index */
+
+static const unsigned char AUX_to_MPH[AUX_MAX] = {
+    MPH_ENVIRONMENTALREVERB,
+    MPH_PRESETREVERB
+};
+
+
+/** \brief This is a private function that validates the effect interface specified by the
+ *  application when it calls EnableEffectSend, IsEnabled, SetSendLevel, or GetSendLevel.
+ *  For the interface to be valid, it has to satisfy these requirements:
+ *   - object is an audio player (MIDI player is not supported yet)
+ *   - audio sink is an output mix
+ *   - interface was exposed at object creation time or by DynamicInterface::AddInterface
+ *   - interface was "gotten" with Object::GetInterface
+ */
+
+static struct EnableLevel *getEnableLevel(IEffectSend *this, const void *pAuxEffect)
+{
+    // Make sure this effect send is on an audio player, not a MIDI player
+    CAudioPlayer *audioPlayer = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
+        (CAudioPlayer *) this->mThis : NULL;
+    if (NULL == audioPlayer) {
+        return NULL;
+    }
+    // Get the output mix for this player
+    COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
+    unsigned aux;
+    if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) {
+        aux = AUX_ENVIRONMENTALREVERB;
+    } else if (pAuxEffect == &outputMix->mPresetReverb.mItf) {
+        aux = AUX_PRESETREVERB;
+    } else {
+        SL_LOGE("EffectSend on unknown aux effect %p", pAuxEffect);
+        return NULL;
+    }
+    assert(aux < AUX_MAX);
+    // Validate that the application has a valid interface for the effect.  The interface must have
+    // been exposed at object creation time or by DynamicInterface::AddInterface, and it also must
+    // have been "gotten" with Object::GetInterface.
+    unsigned MPH = AUX_to_MPH[aux];
+    int index = MPH_to_OutputMix[MPH];
+    if (0 > index) {
+        SL_LOGE("EffectSend aux=%u MPH=%u", aux, MPH);
+        return NULL;
+    }
+    unsigned mask = 1 << index;
+    object_lock_shared(&outputMix->mObject);
+    SLuint32 state = outputMix->mObject.mInterfaceStates[index];
+    mask &= outputMix->mObject.mGottenMask;
+    object_unlock_shared(&outputMix->mObject);
+    switch (state) {
+    case INTERFACE_EXPOSED:
+    case INTERFACE_ADDED:
+    case INTERFACE_SUSPENDED:
+    case INTERFACE_SUSPENDING:
+    case INTERFACE_RESUMING_1:
+    case INTERFACE_RESUMING_2:
+        if (mask) {
+            return &this->mEnableLevels[aux];
+        }
+        SL_LOGE("EffectSend no GetInterface yet");
+        break;
+    default:
+        SL_LOGE("EffectSend invalid interface state %lu", state);
+        break;
+    }
+    return NULL;
+}
+
+#if defined(ANDROID) && !defined(USE_BACKPORT)
+/** \brief This is a private function that translates an Android effect framework status code
+ *  to the SL ES result code used in the EnableEffectSend() function of the SLEffectSendItf
+ *  interface.
+ */
+static SLresult translateEnableFxSendError(android::status_t status) {
+    switch (status) {
+    case android::NO_ERROR:
+        return SL_RESULT_SUCCESS;
+    case android::INVALID_OPERATION:
+    case android::BAD_VALUE:
+    default:
+        SL_LOGE("EffectSend status %u", status);
+        return SL_RESULT_RESOURCE_ERROR;
+    }
+}
+#endif
+
+
+static SLresult IEffectSend_EnableEffectSend(SLEffectSendItf self,
+    const void *pAuxEffect, SLboolean enable, SLmillibel initialLevel)
+{
+    SL_ENTER_INTERFACE
+
+    if (!((SL_MILLIBEL_MIN <= initialLevel) && (initialLevel <= 0))) {
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else {
+        IEffectSend *this = (IEffectSend *) self;
+        struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect);
+        if (NULL == enableLevel) {
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else {
+            interface_lock_exclusive(this);
+            enableLevel->mEnable = SL_BOOLEAN_FALSE != enable; // normalize
+            enableLevel->mSendLevel = initialLevel;
+#if !defined(ANDROID) || defined(USE_BACKPORT)
+            result = SL_RESULT_SUCCESS;
+#else
+            // TODO do not repeat querying of CAudioPlayer, done inside getEnableLevel()
+            CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
+                    (CAudioPlayer *) this->mThis : NULL;
+            // note that if this was a MIDI player, getEnableLevel would have returned NULL
+            assert(NULL != ap);
+            // check which effect the send is attached to, attach and set level
+            COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap);
+            // the initial send level set here is the total energy on the aux bus,
+            //  so it must take into account the player volume level
+            if (pAuxEffect == &outputMix->mPresetReverb.mItf) {
+                result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable,
+                    outputMix->mPresetReverb.mPresetReverbEffect,
+                    initialLevel + ap->mVolume.mLevel));
+            } else if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) {
+                result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable,
+                    outputMix->mEnvironmentalReverb.mEnvironmentalReverbEffect,
+                    initialLevel + ap->mVolume.mLevel));
+            } else {
+                SL_LOGE("EffectSend unknown aux effect %p", pAuxEffect);
+                result = SL_RESULT_PARAMETER_INVALID;
+            }
+#endif
+            interface_unlock_exclusive(this);
+        }
+    }
+
+    SL_LEAVE_INTERFACE
+}
+
+
+static SLresult IEffectSend_IsEnabled(SLEffectSendItf self,
+    const void *pAuxEffect, SLboolean *pEnable)
+{
+    SL_ENTER_INTERFACE
+
+    if (NULL == pEnable) {
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else {
+        IEffectSend *this = (IEffectSend *) self;
+        struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect);
+        if (NULL == enableLevel) {
+            *pEnable = SL_BOOLEAN_FALSE;
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else {
+            interface_lock_shared(this);
+            SLboolean enable = enableLevel->mEnable;
+            interface_unlock_shared(this);
+            *pEnable = enable;
+            result = SL_RESULT_SUCCESS;
+        }
+    }
+
+    SL_LEAVE_INTERFACE
+}
+
+
+static SLresult IEffectSend_SetDirectLevel(SLEffectSendItf self, SLmillibel directLevel)
+{
+    SL_ENTER_INTERFACE
+
+    if (!((SL_MILLIBEL_MIN <= directLevel) && (directLevel <= 0))) {
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else {
+        IEffectSend *this = (IEffectSend *) 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);
+#else
+                interface_unlock_exclusive(this);
+#endif
+            } else {
+                interface_unlock_exclusive(this);
+            }
+        } else {
+            // MIDI player is silently not supported
+            interface_unlock_exclusive(this);
+        }
+        result = SL_RESULT_SUCCESS;
+    }
+
+    SL_LEAVE_INTERFACE
+}
+
+
+static SLresult IEffectSend_GetDirectLevel(SLEffectSendItf self, SLmillibel *pDirectLevel)
+{
+    SL_ENTER_INTERFACE
+
+    if (NULL == pDirectLevel) {
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else {
+        IEffectSend *this = (IEffectSend *) self;
+        interface_lock_shared(this);
+        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
+                (CAudioPlayer *) this->mThis : NULL;
+        if (NULL != ap) {
+            *pDirectLevel = ap->mDirectLevel;
+        } else {
+            // MIDI player is silently not supported
+            *pDirectLevel = 0;
+        }
+        interface_unlock_shared(this);
+        result = SL_RESULT_SUCCESS;
+    }
+
+    SL_LEAVE_INTERFACE
+}
+
+
+static SLresult IEffectSend_SetSendLevel(SLEffectSendItf self, const void *pAuxEffect,
+    SLmillibel sendLevel)
+{
+    SL_ENTER_INTERFACE
+
+    if (!((SL_MILLIBEL_MIN <= sendLevel) && (sendLevel <= 0))) {
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else {
+        IEffectSend *this = (IEffectSend *) self;
+        struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect);
+        if (NULL == enableLevel) {
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else {
+            result = SL_RESULT_SUCCESS;
+            // EnableEffectSend is exclusive, so this has to be also
+            interface_lock_exclusive(this);
+            enableLevel->mSendLevel = sendLevel;
+#if defined(ANDROID) && !defined(USE_BACKPORT)
+            CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
+                    (CAudioPlayer *) this->mThis : NULL;
+            if (NULL != ap) {
+                // the send level set here is the total energy on the aux bus, so it must take
+                // into account the player volume level
+                result = android_fxSend_setSendLevel(ap, sendLevel + ap->mVolume.mLevel);
+            }
+#endif
+            interface_unlock_exclusive(this);
+
+        }
+    }
+
+    SL_LEAVE_INTERFACE
+}
+
+
+static SLresult IEffectSend_GetSendLevel(SLEffectSendItf self, const void *pAuxEffect,
+    SLmillibel *pSendLevel)
+{
+    SL_ENTER_INTERFACE
+
+    if (NULL == pSendLevel) {
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else {
+        IEffectSend *this = (IEffectSend *) self;
+        struct EnableLevel *enableLevel = getEnableLevel(this, pAuxEffect);
+        if (NULL == enableLevel) {
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else {
+            interface_lock_shared(this);
+            SLmillibel sendLevel = enableLevel->mSendLevel;
+            interface_unlock_shared(this);
+            *pSendLevel = sendLevel;
+            result = SL_RESULT_SUCCESS;
+        }
+    }
+
+    SL_LEAVE_INTERFACE
+}
+
+
+static const struct SLEffectSendItf_ IEffectSend_Itf = {
+    IEffectSend_EnableEffectSend,
+    IEffectSend_IsEnabled,
+    IEffectSend_SetDirectLevel,
+    IEffectSend_GetDirectLevel,
+    IEffectSend_SetSendLevel,
+    IEffectSend_GetSendLevel
+};
+
+void IEffectSend_init(void *self)
+{
+    IEffectSend *this = (IEffectSend *) self;
+    this->mItf = &IEffectSend_Itf;
+    struct EnableLevel *enableLevel = this->mEnableLevels;
+    unsigned aux;
+    for (aux = 0; aux < AUX_MAX; ++aux, ++enableLevel) {
+        enableLevel->mEnable = SL_BOOLEAN_FALSE;
+        enableLevel->mSendLevel = SL_MILLIBEL_MIN;
+    }
+}