161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/*
261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *
461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * you may not use this file except in compliance with the License.
661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * You may obtain a copy of the License at
761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *
861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *
1061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Unless required by applicable law or agreed to in writing, software
1161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
1261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * See the License for the specific language governing permissions and
1461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * limitations under the License.
1561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten */
1661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
1761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/* EffectSend implementation */
1861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
1961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten#include "sles_allinclusive.h"
2061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
21343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
22343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Maps AUX index to OutputMix interface index */
23510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
24510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic const unsigned char AUX_to_MPH[AUX_MAX] = {
25510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    MPH_ENVIRONMENTALREVERB,
26510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    MPH_PRESETREVERB
27510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten};
28510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
29343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
30e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten/** \brief This is a private function that validates the effect interface specified by the
31e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten *  application when it calls EnableEffectSend, IsEnabled, SetSendLevel, or GetSendLevel.
32e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten *  For the interface to be valid, it has to satisfy these requirements:
33e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten *   - object is an audio player (MIDI player is not supported yet)
34e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten *   - audio sink is an output mix
35e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten *   - interface was exposed at object creation time or by DynamicInterface::AddInterface
36e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten *   - interface was "gotten" with Object::GetInterface
37e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten */
38343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
39bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenstatic struct EnableLevel *getEnableLevel(IEffectSend *thiz, const void *pAuxEffect)
4061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
41343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten    // Make sure this effect send is on an audio player, not a MIDI player
42bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    CAudioPlayer *audioPlayer = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
43bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (CAudioPlayer *) thiz->mThis : NULL;
449e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    if (NULL == audioPlayer) {
45343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten        return NULL;
469e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    }
47f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // Get the output mix for this player
48f51dba65751107c930759938775b75531ec1f330Glenn Kasten    COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
49510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned aux;
509e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) {
51510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        aux = AUX_ENVIRONMENTALREVERB;
529e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    } else if (pAuxEffect == &outputMix->mPresetReverb.mItf) {
53510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        aux = AUX_PRESETREVERB;
549e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    } else {
559e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        SL_LOGE("EffectSend on unknown aux effect %p", pAuxEffect);
56510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        return NULL;
579e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    }
58510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(aux < AUX_MAX);
59e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten    // Validate that the application has a valid interface for the effect.  The interface must have
60e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten    // been exposed at object creation time or by DynamicInterface::AddInterface, and it also must
61e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten    // have been "gotten" with Object::GetInterface.
629e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    unsigned MPH = AUX_to_MPH[aux];
639e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    int index = MPH_to_OutputMix[MPH];
649e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    if (0 > index) {
659e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        SL_LOGE("EffectSend aux=%u MPH=%u", aux, MPH);
66510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        return NULL;
679e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    }
68510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned mask = 1 << index;
69510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_shared(&outputMix->mObject);
70510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint32 state = outputMix->mObject.mInterfaceStates[index];
71510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    mask &= outputMix->mObject.mGottenMask;
72510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_unlock_shared(&outputMix->mObject);
73510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
74510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_EXPOSED:
75510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_ADDED:
76510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_SUSPENDED:
77510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_SUSPENDING:
78510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_RESUMING_1:
79510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_RESUMING_2:
809e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        if (mask) {
81bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            return &thiz->mEnableLevels[aux];
829e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        }
839e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        SL_LOGE("EffectSend no GetInterface yet");
84510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
85510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:
86a8179ea15c4ff78db589d742b135649f0eda7ef2Glenn Kasten        SL_LOGE("EffectSend invalid interface state %u", state);
87510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
88510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
8961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return NULL;
9061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
9161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
92faf90312d2156acbf27c62e114fd180708aa7654Glenn Kasten#if defined(ANDROID)
93172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi/** \brief This is a private function that translates an Android effect framework status code
94172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi *  to the SL ES result code used in the EnableEffectSend() function of the SLEffectSendItf
95172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi *  interface.
96172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi */
97172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivistatic SLresult translateEnableFxSendError(android::status_t status) {
98172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi    switch (status) {
999e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    case android::NO_ERROR:
1009e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        return SL_RESULT_SUCCESS;
1019e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    case android::INVALID_OPERATION:
1029e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    case android::BAD_VALUE:
1039e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    default:
1049e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        SL_LOGE("EffectSend status %u", status);
1059e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        return SL_RESULT_RESOURCE_ERROR;
106172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi    }
107172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi}
10891bfd060b992810ca092f640f77f795bc3d008beGlenn Kasten#endif
109172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi
110ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
11161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IEffectSend_EnableEffectSend(SLEffectSendItf self,
11261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const void *pAuxEffect, SLboolean enable, SLmillibel initialLevel)
11361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
114ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
115ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
116ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    //if (!((SL_MILLIBEL_MIN <= initialLevel) && (initialLevel <= 0))) {
117ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    // comparison (SL_MILLIBEL_MIN <= initialLevel) is always true due to range of SLmillibel
118ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    if (!(initialLevel <= 0)) {
119ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
120ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
121bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IEffectSend *thiz = (IEffectSend *) self;
122bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
123ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == enableLevel) {
124ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
125ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
126bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_lock_exclusive(thiz);
127ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            enableLevel->mEnable = SL_BOOLEAN_FALSE != enable; // normalize
128ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            enableLevel->mSendLevel = initialLevel;
129faf90312d2156acbf27c62e114fd180708aa7654Glenn Kasten#if !defined(ANDROID)
130ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_SUCCESS;
131172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi#else
132172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi            // TODO do not repeat querying of CAudioPlayer, done inside getEnableLevel()
133bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
134bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    (CAudioPlayer *) thiz->mThis : NULL;
1359e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            // note that if this was a MIDI player, getEnableLevel would have returned NULL
1369e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            assert(NULL != ap);
137172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi            // check which effect the send is attached to, attach and set level
1389e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            COutputMix *outputMix = CAudioPlayer_GetOutputMix(ap);
1399e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            // the initial send level set here is the total energy on the aux bus,
1409e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            //  so it must take into account the player volume level
1419e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            if (pAuxEffect == &outputMix->mPresetReverb.mItf) {
1429e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable,
1439e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                    outputMix->mPresetReverb.mPresetReverbEffect,
1449e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                    initialLevel + ap->mVolume.mLevel));
1459e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            } else if (pAuxEffect == &outputMix->mEnvironmentalReverb.mItf) {
1469e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                result = translateEnableFxSendError(android_fxSend_attach(ap, (bool) enable,
1479e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                    outputMix->mEnvironmentalReverb.mEnvironmentalReverbEffect,
1489e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                    initialLevel + ap->mVolume.mLevel));
149172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi            } else {
1509e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                SL_LOGE("EffectSend unknown aux effect %p", pAuxEffect);
1519e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                result = SL_RESULT_PARAMETER_INVALID;
152172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi            }
153172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi#endif
154bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
155ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
156ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
157ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
158ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
15961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
16061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
161ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
16261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IEffectSend_IsEnabled(SLEffectSendItf self,
16361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const void *pAuxEffect, SLboolean *pEnable)
16461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
165ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
166ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
167ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pEnable) {
168ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
169ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
170bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IEffectSend *thiz = (IEffectSend *) self;
171bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
172ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == enableLevel) {
1739e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            *pEnable = SL_BOOLEAN_FALSE;
174ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
175ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
176bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_lock_shared(thiz);
177ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLboolean enable = enableLevel->mEnable;
178bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_shared(thiz);
179ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            *pEnable = enable;
180ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_SUCCESS;
181ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
182ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
183ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
184ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
18561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
18661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
187ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
188d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IEffectSend_SetDirectLevel(SLEffectSendItf self, SLmillibel directLevel)
18961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
190ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
191ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
192ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    //if (!((SL_MILLIBEL_MIN <= directLevel) && (directLevel <= 0))) {
193ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    // comparison (SL_MILLIBEL_MIN <= directLevel) is always true due to range of SLmillibel
194ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    if (!(directLevel <= 0)) {
195ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
196ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
197bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IEffectSend *thiz = (IEffectSend *) self;
198bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
199bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
200bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                (CAudioPlayer *) thiz->mThis : NULL;
201fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi        if (NULL != ap) {
202fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi            SLmillibel oldDirectLevel = ap->mDirectLevel;
203fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi            if (oldDirectLevel != directLevel) {
204fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi                ap->mDirectLevel = directLevel;
205fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi#if defined(ANDROID)
206172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi                ap->mAmplFromDirectLevel = sles_to_android_amplification(directLevel);
207bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                interface_unlock_exclusive_attributes(thiz, ATTR_GAIN);
208fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi#else
209bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                interface_unlock_exclusive(thiz);
21091bfd060b992810ca092f640f77f795bc3d008beGlenn Kasten#endif
211fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi            } else {
212bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                interface_unlock_exclusive(thiz);
213fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi            }
214172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi        } else {
2159e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            // MIDI player is silently not supported
216bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
217172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi        }
2189e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        result = SL_RESULT_SUCCESS;
219ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
220ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
221ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
22261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
22361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
224ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
225d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IEffectSend_GetDirectLevel(SLEffectSendItf self, SLmillibel *pDirectLevel)
22661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
227ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
228ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
229ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pDirectLevel) {
230ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
231ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
232bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IEffectSend *thiz = (IEffectSend *) self;
233bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_shared(thiz);
234bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
235bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                (CAudioPlayer *) thiz->mThis : NULL;
236fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi        if (NULL != ap) {
237fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi            *pDirectLevel = ap->mDirectLevel;
238fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi        } else {
2399e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            // MIDI player is silently not supported
2409e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            *pDirectLevel = 0;
241fef6033d852daec8d88060b252e72f322724dca1Jean-Michel Trivi        }
242bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_shared(thiz);
2439e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        result = SL_RESULT_SUCCESS;
244ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
245ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
246ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
24761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
24861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
249ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
250e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenstatic SLresult IEffectSend_SetSendLevel(SLEffectSendItf self, const void *pAuxEffect,
251e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLmillibel sendLevel)
25261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
253ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
254ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
255ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    //if (!((SL_MILLIBEL_MIN <= sendLevel) && (sendLevel <= 0))) {
256ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    // comparison (SL_MILLIBEL_MIN <= sendLevel) is always true due to range of SLmillibel
257ad79bbfd16ba81a45842179178332fbd06ad365eJean-Michel Trivi    if (!(sendLevel <= 0)) {
258ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
260bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IEffectSend *thiz = (IEffectSend *) self;
261bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
262ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == enableLevel) {
263ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
264ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
265a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            result = SL_RESULT_SUCCESS;
266ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // EnableEffectSend is exclusive, so this has to be also
267bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_lock_exclusive(thiz);
268ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            enableLevel->mSendLevel = sendLevel;
269faf90312d2156acbf27c62e114fd180708aa7654Glenn Kasten#if defined(ANDROID)
270bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
271bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    (CAudioPlayer *) thiz->mThis : NULL;
272172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi            if (NULL != ap) {
273ca325fa86f9e52d8300490eee102a3c1188f6bdcJean-Michel Trivi                // the send level set here is the total energy on the aux bus, so it must take
274ca325fa86f9e52d8300490eee102a3c1188f6bdcJean-Michel Trivi                // into account the player volume level
275ca325fa86f9e52d8300490eee102a3c1188f6bdcJean-Michel Trivi                result = android_fxSend_setSendLevel(ap, sendLevel + ap->mVolume.mLevel);
276172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi            }
277172e4da556ad3cb1d2a06cfa019903310aa291d5Jean-Michel Trivi#endif
278bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
279ca325fa86f9e52d8300490eee102a3c1188f6bdcJean-Michel Trivi
280ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
281ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
282ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
283ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
28461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
28561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
286ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
287e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenstatic SLresult IEffectSend_GetSendLevel(SLEffectSendItf self, const void *pAuxEffect,
288e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLmillibel *pSendLevel)
28961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
290ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
291ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
292ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pSendLevel) {
293ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
294ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
295bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IEffectSend *thiz = (IEffectSend *) self;
296bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        struct EnableLevel *enableLevel = getEnableLevel(thiz, pAuxEffect);
297ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == enableLevel) {
298ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
299ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
300bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_lock_shared(thiz);
301ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLmillibel sendLevel = enableLevel->mSendLevel;
302bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_shared(thiz);
303ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            *pSendLevel = sendLevel;
304ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_SUCCESS;
305ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
306ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
307ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
308ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
30961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
31061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
311ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
31261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic const struct SLEffectSendItf_ IEffectSend_Itf = {
31361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_EnableEffectSend,
31461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_IsEnabled,
31561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_SetDirectLevel,
31661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_GetDirectLevel,
31761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_SetSendLevel,
31861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_GetSendLevel
31961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten};
32061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
32161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenvoid IEffectSend_init(void *self)
32261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
323bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IEffectSend *thiz = (IEffectSend *) self;
324bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IEffectSend_Itf;
325bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    struct EnableLevel *enableLevel = thiz->mEnableLevels;
3266a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    unsigned aux;
3276a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    for (aux = 0; aux < AUX_MAX; ++aux, ++enableLevel) {
3286a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        enableLevel->mEnable = SL_BOOLEAN_FALSE;
3296a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        enableLevel->mSendLevel = SL_MILLIBEL_MIN;
3306a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    }
33161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
332