Android Audio代碼分析21 – 創建AudioEffect對象 – Android移動開發技術文章_手機開發 Android移動開發教學課程

 

今天來看看AudioEffect的構造,以及相關的一些函數。

 

 

*****************************************源碼*************************************************

    //Test case 1.0: test constructor from effect type and get effect ID

    @LargeTest

    public void test1_0ConstructorFromType() throws Exception {

        boolean result = true;

        String msg = "test1_0ConstructorFromType()";

        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();

        assertTrue(msg+": no effects found", (desc.length != 0));

        try {

            AudioEffect effect = new AudioEffect(desc[0].type,

                    AudioEffect.EFFECT_TYPE_NULL,

                    0,

                    0);

            assertNotNull(msg + ": could not create AudioEffect", effect);

            try {

                assertTrue(msg +": invalid effect ID", (effect.getId() != 0));

            } catch (IllegalStateException e) {

                msg = msg.concat(": AudioEffect not initialized");

                result = false;

            } finally {

                effect.release();

            }

        } catch (IllegalArgumentException e) {

            msg = msg.concat(": Effect not found: "+desc[0].name);

            result = false;

        } catch (UnsupportedOperationException e) {

            msg = msg.concat(": Effect library not loaded");

            result = false;

        }

        assertTrue(msg, result);

    }

**********************************************************************************************

源碼路徑:

frameworks\base\media\tests\mediaframeworktest\src\com\android\mediaframeworktest\functional\MediaAudioEffectTest.java

 

 

#######################說明################################

    //Test case 1.0: test constructor from effect type and get effect ID

    @LargeTest

    public void test1_0ConstructorFromType() throws Exception {

        boolean result = true;

        String msg = "test1_0ConstructorFromType()";

        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();

        assertTrue(msg+": no effects found", (desc.length != 0));

        try {

            AudioEffect effect = new AudioEffect(desc[0].type,

                    AudioEffect.EFFECT_TYPE_NULL,

                    0,

                    0);

+++++++++++++++++++++++++++++++AudioEffect+++++++++++++++++++++++++++++++++

    /**

     * Class constructor.

     *

     * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB},

     *            {@link #EFFECT_TYPE_EQUALIZER} … Types corresponding to

     *            built-in effects are defined by AudioEffect class. Other types

     *            can be specified provided they correspond an existing OpenSL

     *            ES interface ID and the corresponsing effect is available on

     *            the platform. If an unspecified effect type is requested, the

     *            constructor with throw the IllegalArgumentException. This

     *            parameter can be set to {@link #EFFECT_TYPE_NULL} in which

     *            case only the uuid will be used to select the effect.

     * @param uuid unique identifier of a particular effect implementation.

     *            Must be specified if the caller wants to use a particular

     *            implementation of an effect type. This parameter can be set to

     *            {@link #EFFECT_TYPE_NULL} in which case only the type will

     *            be used to select the effect.

     * @param priority the priority level requested by the application for

     *            controlling the effect engine. As the same effect engine can

     *            be shared by several applications, this parameter indicates

     *            how much the requesting application needs control of effect

     *            parameters. The normal priority is 0, above normal is a

     *            positive number, below normal a negative number.

     * @param audioSession system wide unique audio session identifier. If audioSession

     *            is not 0, the effect will be attached to the MediaPlayer or

     *            AudioTrack in the same audio session. Otherwise, the effect

     *            will apply to the output mix.

     *

     * @throws java.lang.IllegalArgumentException

     * @throws java.lang.UnsupportedOperationException

     * @throws java.lang.RuntimeException

     * @hide

     */

 

 

    public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)

            throws IllegalArgumentException, UnsupportedOperationException,

            RuntimeException {

        int[] id = new int[1];

        Descriptor[] desc = new Descriptor[1];

        // native initialization

        int initResult = native_setup(new WeakReference<AudioEffect>(this),

                type.toString(), uuid.toString(), priority, audioSession, id,

                desc);

+++++++++++++++++++++++++android_media_AudioEffect_native_setup+++++++++++++++++++++++++++++++++++++++

static jint

android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,

        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)

{

    LOGV("android_media_AudioEffect_native_setup");

    AudioEffectJniStorage* lpJniStorage = NULL;

    int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;

    AudioEffect* lpAudioEffect = NULL;

    jint* nId = NULL;

    const char *typeStr = NULL;

    const char *uuidStr = NULL;

    effect_descriptor_t desc;

    jobject jdesc;

    char str[EFFECT_STRING_LEN_MAX];

    jstring jdescType;

    jstring jdescUuid;

    jstring jdescConnect;

    jstring jdescName;

    jstring jdescImplementor;

 

 

    if (type != NULL) {

        typeStr = env->GetStringUTFChars(type, NULL);

        if (typeStr == NULL) {  // Out of memory

            jniThrowException(env, "java/lang/RuntimeException", "Out of memory");

            goto setup_failure;

        }

    }

 

 

    if (uuid != NULL) {

        uuidStr = env->GetStringUTFChars(uuid, NULL);

        if (uuidStr == NULL) {  // Out of memory

            jniThrowException(env, "java/lang/RuntimeException", "Out of memory");

            goto setup_failure;

        }

    }

 

 

// type 和uuid 必須有一個不為空

// 否則,沒辦法確定用哪個effect lib

    if (typeStr == NULL && uuidStr == NULL) {

        lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;

        goto setup_failure;

    }

 

 

    lpJniStorage = new AudioEffectJniStorage();

    if (lpJniStorage == NULL) {

        LOGE("setup: Error creating JNI Storage");

        goto setup_failure;

    }

++++++++++++++++++++++++++++AudioEffectJniStorage++++++++++++++++++++++++++++++++++++

struct effect_callback_cookie {

    jclass      audioEffect_class;  // AudioEffect class

    jobject     audioEffect_ref;    // AudioEffect object instance

 };

 class AudioEffectJniStorage {

    public:

        effect_callback_cookie mCallbackData;

 

 

    AudioEffectJniStorage() {

    }

 

 

    ~AudioEffectJniStorage() {

    }

 

 

};

—————————-AudioEffectJniStorage————————————

 

 

    lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);

    // we use a weak reference so the AudioEffect object can be garbage collected.

    lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);

 

 

    LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",

            lpJniStorage,

            lpJniStorage->mCallbackData.audioEffect_ref,

            lpJniStorage->mCallbackData.audioEffect_class,

            &lpJniStorage->mCallbackData);

 

 

    if (jId == NULL) {

        LOGE("setup: NULL java array for id pointer");

        lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;

        goto setup_failure;

    }

 

 

    // create the native AudioEffect object

    lpAudioEffect = new AudioEffect(typeStr,

                                    uuidStr,

                                    priority,

                                    effectCallback,

                                    &lpJniStorage->mCallbackData,

                                    sessionId,

                                    0);

    if (lpAudioEffect == NULL) {

        LOGE("Error creating AudioEffect");

        goto setup_failure;

    }

++++++++++++++++++++++++++++native AudioEffect++++++++++++++++++++++++++++++++++++

AudioEffect::AudioEffect(const char *typeStr,

                const char *uuidStr,

                int32_t priority,

                effect_callback_t cbf,

                void* user,

                int sessionId,

                audio_io_handle_t output

                )

    : mStatus(NO_INIT)

{

    effect_uuid_t type;

    effect_uuid_t *pType = NULL;

    effect_uuid_t uuid;

    effect_uuid_t *pUuid = NULL;

 

 

    LOGV("Constructor string\n – type: %s\n – uuid: %s", typeStr, uuidStr);

 

 

    if (typeStr != NULL) {

        if (stringToGuid(typeStr, &type) == NO_ERROR) {

            pType = &type;

        }

    }

 

 

    if (uuidStr != NULL) {

        if (stringToGuid(uuidStr, &uuid) == NO_ERROR) {

            pUuid = &uuid;

        }

    }

 

 

    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output);

+++++++++++++++++++++++++++++AudioEffect::set+++++++++++++++++++++++++++++++++++

status_t AudioEffect::set(const effect_uuid_t *type,

                const effect_uuid_t *uuid,

                int32_t priority,

                effect_callback_t cbf,

                void* user,

                int sessionId,

                audio_io_handle_t output)

{

    sp<IEffect> iEffect;

    sp<IMemory> cblk;

    int enabled;

 

 

    LOGV("set %p mUserData: %p", this, user);

 

 

// 如果effect 對象已經被創建瞭,返回無效操作

    if (mIEffect != 0) {

        LOGW("Effect already in use");

        return INVALID_OPERATION;

    }

 

 

    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();

    if (audioFlinger == 0) {

        LOGE("set(): Could not get audioflinger");

        return NO_INIT;

    }

 

 

// 再一次檢查type和uuid

    if (type == NULL && uuid == NULL) {

        LOGW("Must specify at least type or uuid");

        return BAD_VALUE;

    }

 

 

    mPriority = priority;

// cbf其實是函數effectCallback

    mCbf = cbf;

+++++++++++++++++++++++++++++effectCallback+++++++++++++++++++++++++++++++++++

static void effectCallback(int event, void* user, void *info) {

 

 

    effect_param_t *p;

    int arg1 = 0;

    int arg2 = 0;

    jobject obj = NULL;

    jbyteArray array = NULL;

    jbyte *bytes;

    bool param;

    size_t size;

 

 

    effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;

    JNIEnv *env = AndroidRuntime::getJNIEnv();

 

 

    LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",

            callbackInfo,

            callbackInfo->audioEffect_ref,

            callbackInfo->audioEffect_class);

 

 

    if (!user || !env) {

        LOGW("effectCallback error user %p, env %p", user, env);

        return;

    }

 

 

    switch (event) {

    case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:

        if (info == 0) {

            LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");

            goto effectCallback_Exit;

        }

        param = *(bool *)info;

        arg1 = (int)param;

        LOGV("EVENT_CONTROL_STATUS_CHANGED");

        break;

    case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:

        if (info == 0) {

            LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");

            goto effectCallback_Exit;

        }

        param = *(bool *)info;

        arg1 = (int)param;

        LOGV("EVENT_ENABLE_STATUS_CHANGED");

        break;

    case AudioEffect::EVENT_PARAMETER_CHANGED:

        if (info == 0) {

            LOGW("EVENT_PARAMETER_CHANGED info == NULL");

            goto effectCallback_Exit;

        }

        p = (effect_param_t *)info;

        if (p->psize == 0 || p->vsize == 0) {

            goto effectCallback_Exit;

        }

        // arg1 contains offset of parameter value from start of byte array

        arg1 = sizeof(effect_param_t) + ((p->psize – 1) / sizeof(int) + 1) * sizeof(int);

        size = arg1 + p->vsize;

        array = env->NewByteArray(size);

        if (array == NULL) {

            LOGE("effectCallback: Couldn't allocate byte array for parameter data");

            goto effectCallback_Exit;

        }

        bytes = env->GetByteArrayElements(array, NULL);

        memcpy(bytes, p, size);

        env->ReleaseByteArrayElements(array, bytes, 0);

        obj = array;

        LOGV("EVENT_PARAMETER_CHANGED");

       break;

    case AudioEffect::EVENT_ERROR:

        LOGW("EVENT_ERROR");

        break;

    }

 

 

    env->CallStaticVoidMethod(

        callbackInfo->audioEffect_class,

        fields.midPostNativeEvent,

        callbackInfo->audioEffect_ref, event, arg1, arg2, obj);

 

 

effectCallback_Exit:

    if (array) {

        env->DeleteLocalRef(array);

    }

 

 

    if (env->ExceptionCheck()) {

        env->ExceptionDescribe();

        env->ExceptionClear();

    }

}

—————————–effectCallback———————————–

// user其實是AudioEffectJniStorage對象中mCallbackData成員的地址

    mUserData = user;

    mSessionId = sessionId;

 

 

    memset(&mDescriptor, 0, sizeof(effect_descriptor_t));

    memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t));

    memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t));

 

 

    if (type != NULL) {

        memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t));

    }

    if (uuid != NULL) {

        memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t));

    }

 

 

    mIEffectClient = new EffectClient(this);

+++++++++++++++++++++++++++++EffectClient+++++++++++++++++++++++++++++++++++

     // Implements the IEffectClient interface

    class EffectClient : public android::BnEffectClient,  public android::IBinder::DeathRecipient

    {

    public:

 

 

        EffectClient(AudioEffect *effect) : mEffect(effect){}

 

 

        // IEffectClient

        virtual void controlStatusChanged(bool controlGranted) {

            mEffect->controlStatusChanged(controlGranted);

        }

        virtual void enableStatusChanged(bool enabled) {

            mEffect->enableStatusChanged(enabled);

        }

        virtual void commandExecuted(uint32_t cmdCode,

                                     uint32_t cmdSize,

                                     void *pCmdData,

                                     uint32_t replySize,

                                     void *pReplyData) {

            mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);

        }

 

 

        // IBinder::DeathRecipient

        virtual void binderDied(const wp<IBinder>& who) {mEffect->binderDied();}

 

 

    private:

        AudioEffect *mEffect;

    };

—————————–EffectClient———————————–

 

 

    iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,

            mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled);

 

 

    if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {

        LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);

        return mStatus;

    }

++++++++++++++++++++++++++AudioFlinger::createEffect++++++++++++++++++++++++++++++++++++++

sp<IEffect> AudioFlinger::createEffect(pid_t pid,

        effect_descriptor_t *pDesc,

        const sp<IEffectClient>& effectClient,

        int32_t priority,

        int output,

        int sessionId,

        status_t *status,

        int *id,

        int *enabled)

{

    status_t lStatus = NO_ERROR;

    sp<EffectHandle> handle;

    effect_interface_t itfe;

    effect_descriptor_t desc;

    sp<Client> client;

    wp<Client> wclient;

 

 

    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d",

            pid, effectClient.get(), priority, sessionId, output);

 

 

    if (pDesc == NULL) {

        lStatus = BAD_VALUE;

        goto Exit;

    }

 

 

    // check audio settings permission for global effects

    if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) {

        lStatus = PERMISSION_DENIED;

        goto Exit;

    }

+++++++++++++++++++++++++++++++audio_sessions+++++++++++++++++++++++++++++++++

    // special audio session values

    enum audio_sessions {

        SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream

                                   // (value must be less than 0)

        SESSION_OUTPUT_MIX = 0,    // session for effects applied to output mix. These effects can

                                   // be moved by audio policy manager to another output stream

                                   // (value must be 0)

    };

——————————-audio_sessions———————————

 

 

    // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects

    // that can only be created by audio policy manager (running in same process)

    if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) {

        lStatus = PERMISSION_DENIED;

        goto Exit;

    }

 

 

    // check recording permission for visualizer

    if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||

         memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&

        !recordingAllowed()) {

        lStatus = PERMISSION_DENIED;

        goto Exit;

    }

 

 

    if (output == 0) {

        if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {

            // output must be specified by AudioPolicyManager when using session

            // AudioSystem::SESSION_OUTPUT_STAGE

// 如果sessionId為AudioSystem::SESSION_OUTPUT_STAGE,effect必須綁定到特定的output

            lStatus = BAD_VALUE;

            goto Exit;

        } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {

            // if the output returned by getOutputForEffect() is removed before we lock the

            // mutex below, the call to checkPlaybackThread_l(output) below will detect it

            // and we will exit safely

            output = AudioSystem::getOutputForEffect(&desc);

++++++++++++++++++++++++++++++AudioSystem::getOutputForEffect++++++++++++++++++++++++++++++++++

audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc)

{

    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();

    if (aps == 0) return PERMISSION_DENIED;

    return aps->getOutputForEffect(desc);

+++++++++++++++++++++++++++++AudioPolicyService::getOutputForEffect+++++++++++++++++++++++++++++++++++

audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc)

{

    if (mpPolicyManager == NULL) {

        return NO_INIT;

    }

    Mutex::Autolock _l(mLock);

    return mpPolicyManager->getOutputForEffect(desc);

++++++++++++++++++++++++++++++AudioPolicyManagerBase::getOutputForEffect++++++++++++++++++++++++++++++++++

audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc)

{

    LOGV("getOutputForEffect()");

    // apply simple rule where global effects are attached to the same output as MUSIC streams

// 所有的effect都會被綁定到MUSIT stream上,所以,這兒隻是簡單的將MUSIC stream對應的output返回

    return getOutput(AudioSystem::MUSIC);

}

——————————AudioPolicyManagerBase::getOutputForEffect———————————-

}

—————————–AudioPolicyService::getOutputForEffect———————————–

}

——————————AudioSystem::getOutputForEffect———————————-

        }

    }

 

 

    {

        Mutex::Autolock _l(mLock);

 

 

 

 

        if (!EffectIsNullUuid(&pDesc->uuid)) {

// 如果指定瞭uuid,則根據uuid尋找合適的effect descriptor

            // if uuid is specified, request effect descriptor

            lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);

            if (lStatus < 0) {

                LOGW("createEffect() error %d from EffectGetDescriptor", lStatus);

                goto Exit;

            }

++++++++++++++++++++++++++++++EffectGetDescriptor++++++++++++++++++++++++++++++++++

路徑:frameworks\base\media\libeffects\factory\EffectsFactory.c

 

 

int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)

{

    lib_entry_t *l = NULL;

    effect_descriptor_t *d = NULL;

 

 

// init 函數我們已經看過

// 如果init已經被調用過,再次進入init函數並不會有真正的動作

// 也就是說,初始化操作隻會進行一次

    int ret = init();

    if (ret < 0) {

        return ret;

    }

    if (pDescriptor == NULL || uuid == NULL) {

        return -EINVAL;

    }

    pthread_mutex_lock(&gLibLock);

    ret = findEffect(uuid, &l, &d);

    if (ret == 0) {

        memcpy(pDescriptor, d, sizeof(effect_descriptor_t));

    }

+++++++++++++++++++++++++++++++findEffect+++++++++++++++++++++++++++++++++

int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc)

{

// gLibraryList是保存所有effect lib的列表

    list_elem_t *e = gLibraryList;

    lib_entry_t *l = NULL;

    effect_descriptor_t *d = NULL;

    int found = 0;

    int ret = 0;

 

 

    while (e && !found) {

        l = (lib_entry_t *)e->object;

        list_elem_t *efx = l->effects;

        while (efx) {

            d = (effect_descriptor_t *)efx->object;

// 比較是否與給定的uuid一致

            if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {

                found = 1;

                break;

            }

            efx = efx->next;

        }

        e = e->next;

    }

    if (!found) {

        LOGV("findEffect() effect not found");

        ret = -ENOENT;

    } else {

        LOGV("findEffect() found effect: %s in lib %s", d->name, l->path);

        *lib = l;

        *desc = d;

    }

 

 

    return ret;

}

——————————-findEffect———————————

    pthread_mutex_unlock(&gLibLock);

    return ret;

}

——————————EffectGetDescriptor———————————-

        } else {

            // if uuid is not specified, look for an available implementation

            // of the required type in effect factory

// 如果沒指定uuid,則尋找一個相同類型的可用的effect lib

            if (EffectIsNullUuid(&pDesc->type)) {

                LOGW("createEffect() no effect type");

                lStatus = BAD_VALUE;

                goto Exit;

            }

            uint32_t numEffects = 0;

            effect_descriptor_t d;

            bool found = false;

 

 

            lStatus = EffectQueryNumberEffects(&numEffects);

            if (lStatus < 0) {

                LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);

                goto Exit;

            }

            for (uint32_t i = 0; i < numEffects; i++) {

                lStatus = EffectQueryEffect(i, &desc);

                if (lStatus < 0) {

                    LOGW("createEffect() error %d from EffectQueryEffect", lStatus);

                    continue;

                }

                if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {

                    // If matching type found save effect descriptor. If the session is

                    // 0 and the effect is not auxiliary, continue enumeration in case

                    // an auxiliary version of this effect type is available

// 如果session id為0,即AudioSystem::SESSION_OUTPUT_MIX,

// 若找到的effect為auxiliary,則退出,否則的話就繼續查找

// 以防止存在可用的該類型的auxiliary的effect。

// 也就是說,對於AudioSystem::SESSION_OUTPUT_MIX的session id來說,

// 會優先使用auxiliary的effect。

                    found = true;

                    memcpy(&d, &desc, sizeof(effect_descriptor_t));

                    if (sessionId != AudioSystem::SESSION_OUTPUT_MIX ||

                            (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {

                        break;

                    }

                }

            }

            if (!found) {

                lStatus = BAD_VALUE;

                LOGW("createEffect() effect not found");

                goto Exit;

            }

            // For same effect type, chose auxiliary version over insert version if

            // connect to output mix (Compliance to OpenSL ES)

// 如果不存在可用的該類型的auxiliary的effect,也隻能勉強使用剛才找到的insert的瞭

            if (sessionId == AudioSystem::SESSION_OUTPUT_MIX &&

                    (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {

                memcpy(&desc, &d, sizeof(effect_descriptor_t));

            }

        }

 

 

// auxiliary的effect隻能作用在AudioSystem::SESSION_OUTPUT_MIX的session id上。

        // Do not allow auxiliary effects on a session different from 0 (output mix)

        if (sessionId != AudioSystem::SESSION_OUTPUT_MIX &&

             (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {

            lStatus = INVALID_OPERATION;

            goto Exit;

        }

 

 

        // return effect descriptor

        memcpy(pDesc, &desc, sizeof(effect_descriptor_t));

 

 

        // If output is not specified try to find a matching audio session ID in one of the

        // output threads.

// 如果沒有指定output,則嘗試在output threads中尋找匹配的Session ID。

        // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX

        // because of code checking output when entering the function.

// 此時,如果output仍然為0,則說明session ID即不是SESSION_OUTPUT_STAGE,也不是SESSION_OUTPUT_MIX。

// 因為前面我們做過一個檢查,如果output為0,若session ID是SESSION_OUTPUT_STAGE,則直接退出;

// 若session ID是SESSION_OUTPUT_MIX,則會調用函數AudioSystem::getOutputForEffect來get一個output

// (從最終的實現可知,函數AudioSystem::getOutputForEffect最終返回的是music stream對應的output)。

        if (output == 0) {

             // look for the thread where the specified audio session is present

            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {

                if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {

                    output = mPlaybackThreads.keyAt(i);

                    break;

++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::hasAudioSession++++++++++++++++++++++++++++++++++++

uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)

{

    Mutex::Autolock _l(mLock);

    uint32_t result = 0;

    if (getEffectChain_l(sessionId) != 0) {

        result = EFFECT_SESSION;

    }

 

 

    for (size_t i = 0; i < mTracks.size(); ++i) {

        sp<Track> track = mTracks[i];

// 在創建track的時候,會傳入一個session ID

        if (sessionId == track->sessionId() &&

                !(track->mCblk->flags & CBLK_INVALID_MSK)) {

            result |= TRACK_SESSION;

            break;

        }

    }

 

 

    return result;

}

—————————-AudioFlinger::PlaybackThread::hasAudioSession————————————

                }

            }

            // If no output thread contains the requested session ID, default to

            // first output. The effect chain will be moved to the correct output

            // thread when a track with the same session ID is created

// 如果找不到output,默認使用第一個。

// 如果相同session ID的trak被創建瞭,effect鏈表會被移動到新的track上。

// effect的移動工作在函數AudioFlinger::createTrack中完成見隨後代碼

            if (output == 0 && mPlaybackThreads.size()) {

                output = mPlaybackThreads.keyAt(0);

            }

+++++++++++++++++++++++++++++AudioFlinger::createTrack moveEffectChain_l+++++++++++++++++++++++++++++++++++

        if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {

            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {

                sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);

                if (mPlaybackThreads.keyAt(i) != output) {

                    // prevent same audio session on different output threads

                    uint32_t sessions = t->hasAudioSession(*sessionId);

                    if (sessions & PlaybackThread::TRACK_SESSION) {

                        lStatus = BAD_VALUE;

                        goto Exit;

                    }

                    // check if an effect with same session ID is waiting for a track to be created

                    if (sessions & PlaybackThread::EFFECT_SESSION) {

                        effectThread = t.get();

                    }

                }

            }

            lSessionId = *sessionId;

        } else {

            // if no audio session id is provided, create one here

            lSessionId = nextUniqueId();

            if (sessionId != NULL) {

                *sessionId = lSessionId;

            }

        }

        LOGV("createTrack() lSessionId: %d", lSessionId);

 

 

        track = thread->createTrack_l(client, streamType, sampleRate, format,

                channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);

 

 

        // move effect chain to this output thread if an effect on same session was waiting

        // for a track to be created

        if (lStatus == NO_ERROR && effectThread != NULL) {

            Mutex::Autolock _dl(thread->mLock);

            Mutex::Autolock _sl(effectThread->mLock);

            moveEffectChain_l(lSessionId, effectThread, thread, true);

+++++++++++++++++++++++++++++AudioFlinger::moveEffectChain_l+++++++++++++++++++++++++++++++++++

// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held

status_t AudioFlinger::moveEffectChain_l(int session,

                                   AudioFlinger::PlaybackThread *srcThread,

                                   AudioFlinger::PlaybackThread *dstThread,

                                   bool reRegister)

{

    LOGV("moveEffectChain_l() session %d from thread %p to thread %p",

            session, srcThread, dstThread);

 

 

    sp<EffectChain> chain = srcThread->getEffectChain_l(session);

    if (chain == 0) {

        LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p",

                session, srcThread);

        return INVALID_OPERATION;

    }

 

 

    // remove chain first. This is useful only if reconfiguring effect chain on same output thread,

    // so that a new chain is created with correct parameters when first effect is added. This is

    // otherwise unecessary as removeEffect_l() will remove the chain when last effect is

    // removed.

    srcThread->removeEffectChain_l(chain);

 

 

    // transfer all effects one by one so that new effect chain is created on new thread with

    // correct buffer sizes and audio parameters and effect engines reconfigured accordingly

    int dstOutput = dstThread->id();

    sp<EffectChain> dstChain;

    uint32_t strategy;

    sp<EffectModule> effect = chain->getEffectFromId_l(0);

    while (effect != 0) {

        srcThread->removeEffect_l(effect);

        dstThread->addEffect_l(effect);

        // if the move request is not received from audio policy manager, the effect must be

        // re-registered with the new strategy and output

        if (dstChain == 0) {

            dstChain = effect->chain().promote();

            if (dstChain == 0) {

                LOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());

                srcThread->addEffect_l(effect);

                return NO_INIT;

            }

            strategy = dstChain->strategy();

        }

        if (reRegister) {

            AudioSystem::unregisterEffect(effect->id());

            AudioSystem::registerEffect(&effect->desc(),

                                        dstOutput,

                                        strategy,

                                        session,

                                        effect->id());

++++++++++++++++++++++++++++AudioSystem::registerEffect++++++++++++++++++++++++++++++++++++

status_t AudioSystem::registerEffect(effect_descriptor_t *desc,

                                audio_io_handle_t output,

                                uint32_t strategy,

                                int session,

                                int id)

{

    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();

    if (aps == 0) return PERMISSION_DENIED;

    return aps->registerEffect(desc, output, strategy, session, id);

++++++++++++++++++++++++++++AudioPolicyService::registerEffect++++++++++++++++++++++++++++++++++++

status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,

                                audio_io_handle_t output,

                                uint32_t strategy,

                                int session,

                                int id)

{

    if (mpPolicyManager == NULL) {

        return NO_INIT;

    }

    return mpPolicyManager->registerEffect(desc, output, strategy, session, id);

+++++++++++++++++++++++++++AudioPolicyManagerBase::registerEffect+++++++++++++++++++++++++++++++++++++

status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc,

                                audio_io_handle_t output,

                                uint32_t strategy,

                                int session,

                                int id)

{

    ssize_t index = mOutputs.indexOfKey(output);

    if (index < 0) {

        LOGW("registerEffect() unknown output %d", output);

        return INVALID_OPERATION;

    }

 

 

    if (mTotalEffectsCpuLoad + desc->cpuLoad > getMaxEffectsCpuLoad()) {

        LOGW("registerEffect() CPU Load limit exceeded for Fx %s, CPU %f MIPS",

                desc->name, (float)desc->cpuLoad/10);

        return INVALID_OPERATION;

    }

    if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {

        LOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",

                desc->name, desc->memoryUsage);

        return INVALID_OPERATION;

    }

    mTotalEffectsCpuLoad += desc->cpuLoad;

    mTotalEffectsMemory += desc->memoryUsage;

    LOGV("registerEffect() effect %s, output %d, strategy %d session %d id %d",

            desc->name, output, strategy, session, id);

 

 

    LOGV("registerEffect() CPU %d, memory %d", desc->cpuLoad, desc->memoryUsage);

    LOGV("  total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);

 

 

    EffectDescriptor *pDesc = new EffectDescriptor();

    memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));

    pDesc->mOutput = output;

    pDesc->mStrategy = (routing_strategy)strategy;

    pDesc->mSession = session;

    mEffects.add(id, pDesc);

 

 

    return NO_ERROR;

}

—————————AudioPolicyManagerBase::registerEffect————————————-

}

—————————-AudioPolicyService::registerEffect————————————

}

—————————-AudioSystem::registerEffect————————————

        }

        effect = chain->getEffectFromId_l(0);

    }

 

 

    return NO_ERROR;

}

—————————–AudioFlinger::moveEffectChain_l———————————–

        }

—————————–AudioFlinger::createTrack moveEffectChain_l———————————–

        }

        LOGV("createEffect() got output %d for effect %s", output, desc.name);

        PlaybackThread *thread = checkPlaybackThread_l(output);

        if (thread == NULL) {

            LOGE("createEffect() unknown output thread");

            lStatus = BAD_VALUE;

            goto Exit;

        }

 

 

        // TODO: allow attachment of effect to inputs

 

 

        wclient = mClients.valueFor(pid);

 

 

        if (wclient != NULL) {

            client = wclient.promote();

        } else {

            client = new Client(this, pid);

            mClients.add(pid, client);

        }

 

 

        // create effect on selected output trhead

        handle = thread->createEffect_l(client, effectClient, priority, sessionId,

                &desc, enabled, &lStatus);

        if (handle != 0 && id != NULL) {

            *id = handle->id();

        }

++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::createEffect_l++++++++++++++++++++++++++++++++++

// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held

sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(

        const sp<AudioFlinger::Client>& client,

        const sp<IEffectClient>& effectClient,

        int32_t priority,

        int sessionId,

        effect_descriptor_t *desc,

        int *enabled,

        status_t *status

        )

{

    sp<EffectModule> effect;

    sp<EffectHandle> handle;

    status_t lStatus;

    sp<Track> track;

    sp<EffectChain> chain;

    bool chainCreated = false;

    bool effectCreated = false;

    bool effectRegistered = false;

 

 

    if (mOutput == 0) {

        LOGW("createEffect_l() Audio driver not initialized.");

        lStatus = NO_INIT;

        goto Exit;

    }

 

 

    // Do not allow auxiliary effect on session other than 0

    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&

        sessionId != AudioSystem::SESSION_OUTPUT_MIX) {

        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",

                desc->name, sessionId);

        lStatus = BAD_VALUE;

        goto Exit;

    }

 

 

    // Do not allow effects with session ID 0 on direct output or duplicating threads

    // TODO: add rule for hw accelerated effects on direct outputs with non PCM format

    if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && mType != MIXER) {

        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",

                desc->name, sessionId);

        lStatus = BAD_VALUE;

        goto Exit;

    }

 

 

    LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId);

 

 

    { // scope for mLock

        Mutex::Autolock _l(mLock);

 

 

        // check for existing effect chain with the requested audio session

        chain = getEffectChain_l(sessionId);

        if (chain == 0) {

            // create a new chain for this session

            LOGV("createEffect_l() new effect chain for session %d", sessionId);

            chain = new EffectChain(this, sessionId);

            addEffectChain_l(chain);

+++++++++++++++++++++++++++AudioFlinger::PlaybackThread::addEffectChain_l+++++++++++++++++++++++++++++++++++++

status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)

{

    int session = chain->sessionId();

    int16_t *buffer = mMixBuffer;

    bool ownsBuffer = false;

 

 

    LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);

    if (session > 0) {

        // Only one effect chain can be present in direct output thread and it uses

        // the mix buffer as input

        if (mType != DIRECT) {

            size_t numSamples = mFrameCount * mChannelCount;

            buffer = new int16_t[numSamples];

            memset(buffer, 0, numSamples * sizeof(int16_t));

            LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);

            ownsBuffer = true;

        }

 

 

        // Attach all tracks with same session ID to this chain.

        for (size_t i = 0; i < mTracks.size(); ++i) {

            sp<Track> track = mTracks[i];

            if (session == track->sessionId()) {

                LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);

                track->setMainBuffer(buffer);

            }

        }

 

 

        // indicate all active tracks in the chain

        for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {

            sp<Track> track = mActiveTracks[i].promote();

            if (track == 0) continue;

            if (session == track->sessionId()) {

                LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);

                chain->startTrack();

            }

        }

    }

 

 

    chain->setInBuffer(buffer, ownsBuffer);

    chain->setOutBuffer(mMixBuffer);

    // Effect chain for session AudioSystem::SESSION_OUTPUT_STAGE is inserted at end of effect

    // chains list in order to be processed last as it contains output stage effects

    // Effect chain for session AudioSystem::SESSION_OUTPUT_MIX is inserted before

    // session AudioSystem::SESSION_OUTPUT_STAGE to be processed

    // after track specific effects and before output stage

    // It is therefore mandatory that AudioSystem::SESSION_OUTPUT_MIX == 0 and

    // that AudioSystem::SESSION_OUTPUT_STAGE < AudioSystem::SESSION_OUTPUT_MIX

    // Effect chain for other sessions are inserted at beginning of effect

    // chains list to be processed before output mix effects. Relative order between other

    // sessions is not important

    size_t size = mEffectChains.size();

    size_t i = 0;

    for (i = 0; i < size; i++) {

        if (mEffectChains[i]->sessionId() < session) break;

    }

    mEffectChains.insertAt(chain, i);

 

 

    return NO_ERROR;

}

—————————AudioFlinger::PlaybackThread::addEffectChain_l————————————-

            chain->setStrategy(getStrategyForSession_l(sessionId));

            chainCreated = true;

        } else {

            effect = chain->getEffectFromDesc_l(desc);

        }

 

 

        LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());

 

 

        if (effect == 0) {

            int id = mAudioFlinger->nextUniqueId();

            // Check CPU and memory usage

            lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);

            if (lStatus != NO_ERROR) {

                goto Exit;

            }

            effectRegistered = true;

            // create a new effect module if none present in the chain

            effect = new EffectModule(this, chain, desc, id, sessionId);

            lStatus = effect->status();

            if (lStatus != NO_ERROR) {

                goto Exit;

            }

            lStatus = chain->addEffect_l(effect);

            if (lStatus != NO_ERROR) {

                goto Exit;

            }

            effectCreated = true;

++++++++++++++++++++++++++++AudioFlinger::EffectModule::EffectModule++++++++++++++++++++++++++++++++++++

AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,

                                        const wp<AudioFlinger::EffectChain>& chain,

                                        effect_descriptor_t *desc,

                                        int id,

                                        int sessionId)

    : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),

      mStatus(NO_INIT), mState(IDLE)

{

    LOGV("Constructor %p", this);

    int lStatus;

    sp<ThreadBase> thread = mThread.promote();

    if (thread == 0) {

        return;

    }

    PlaybackThread *p = (PlaybackThread *)thread.get();

 

 

    memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));

 

 

    // create effect engine from effect factory

// 這個函數在看函數queryEffects代碼的時候已經接觸過

    mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface);

 

 

    if (mStatus != NO_ERROR) {

        return;

    }

    lStatus = init();

    if (lStatus < 0) {

        mStatus = lStatus;

        goto Error;

    }

 

 

    LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);

    return;

Error:

    EffectRelease(mEffectInterface);

    mEffectInterface = NULL;

    LOGV("Constructor Error %d", mStatus);

}

—————————-AudioFlinger::EffectModule::EffectModule————————————

 

 

            effect->setDevice(mDevice);

+++++++++++++++++++++++++++AudioFlinger::EffectModule::setDevice+++++++++++++++++++++++++++++++++++++

status_t AudioFlinger::EffectModule::setDevice(uint32_t device)

{

    Mutex::Autolock _l(mLock);

    status_t status = NO_ERROR;

    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {

        // convert device bit field from AudioSystem to EffectApi format.

        device = deviceAudioSystemToEffectApi(device);

        if (device == 0) {

            return BAD_VALUE;

        }

        status_t cmdStatus;

        uint32_t size = sizeof(status_t);

// 在EffectModule的構造函數中,調用函數EffectCreate對mEffectInterface進行賦值:

// mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface);

// 此處調用的command函數其實是調用的具體的effect lib中的command 函數

// 如EffectReverb 中的Reverb_Command函數。

        status = (*mEffectInterface)->command(mEffectInterface,

                                              EFFECT_CMD_SET_DEVICE,

                                              sizeof(uint32_t),

                                              &device,

                                              &size,

                                              &cmdStatus);

        if (status == NO_ERROR) {

            status = cmdStatus;

        }

    }

    return status;

}

—————————AudioFlinger::EffectModule::setDevice————————————-

            effect->setMode(mAudioFlinger->getMode());

        }

        // create effect handle and connect it to effect module

        handle = new EffectHandle(effect, client, effectClient, priority);

        lStatus = effect->addHandle(handle);

        if (enabled) {

            *enabled = (int)effect->isEnabled();

        }

    }

 

 

Exit:

    if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {

        Mutex::Autolock _l(mLock);

        if (effectCreated) {

            chain->removeEffect_l(effect);

        }

        if (effectRegistered) {

            AudioSystem::unregisterEffect(effect->id());

        }

        if (chainCreated) {

            removeEffectChain_l(chain);

        }

        handle.clear();

    }

 

 

    if(status) {

        *status = lStatus;

    }

    return handle;

}

——————————AudioFlinger::PlaybackThread::createEffect_l———————————-

    }

 

 

Exit:

    if(status) {

        *status = lStatus;

    }

    return handle;

}

————————–AudioFlinger::createEffect————————————–

 

 

    mEnabled = (volatile int32_t)enabled;

 

 

    mIEffect = iEffect;

    cblk = iEffect->getCblk();

    if (cblk == 0) {

        mStatus = NO_INIT;

        LOGE("Could not get control block");

        return mStatus;

    }

 

 

    mIEffect = iEffect;

    mCblkMemory = cblk;

    mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer());

    int bufOffset = ((sizeof(effect_param_cblk_t) – 1) / sizeof(int) + 1) * sizeof(int);

    mCblk->buffer = (uint8_t *)mCblk + bufOffset;

 

 

    iEffect->asBinder()->linkToDeath(mIEffectClient);

    LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled);

 

 

    return mStatus;

}

—————————–AudioEffect::set———————————–

}

—————————-native AudioEffect————————————

 

 

    lStatus = translateError(lpAudioEffect->initCheck());

    if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {

        LOGE("AudioEffect initCheck failed %d", lStatus);

        goto setup_failure;

    }

 

 

    nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);

    if (nId == NULL) {

        LOGE("setup: Error retrieving id pointer");

        lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;

        goto setup_failure;

    }

    nId[0] = lpAudioEffect->id();

    env->ReleasePrimitiveArrayCritical(jId, nId, 0);

    nId = NULL;

 

 

    if (typeStr) {

        env->ReleaseStringUTFChars(type, typeStr);

        typeStr = NULL;

    }

 

 

    if (uuidStr) {

        env->ReleaseStringUTFChars(uuid, uuidStr);

        uuidStr = NULL;

    }

 

 

    // get the effect descriptor

    desc = lpAudioEffect->descriptor();

 

 

    AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);

    jdescType = env->NewStringUTF(str);

 

 

    AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);

    jdescUuid = env->NewStringUTF(str);

 

 

    if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {

        jdescConnect = env->NewStringUTF("Auxiliary");

    } else {

        jdescConnect = env->NewStringUTF("Insert");

    }

 

 

    jdescName = env->NewStringUTF(desc.name);

    jdescImplementor = env->NewStringUTF(desc.implementor);

 

 

    jdesc = env->NewObject(fields.clazzDesc,

                           fields.midDescCstor,

                           jdescType,

                           jdescUuid,

                           jdescConnect,

                           jdescName,

                           jdescImplementor);

    env->DeleteLocalRef(jdescType);

    env->DeleteLocalRef(jdescUuid);

    env->DeleteLocalRef(jdescConnect);

    env->DeleteLocalRef(jdescName);

    env->DeleteLocalRef(jdescImplementor);

    if (jdesc == NULL) {

        LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");

        goto setup_failure;

    }

 

 

    env->SetObjectArrayElement(javadesc, 0, jdesc);

 

 

    env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);

 

 

    env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);

 

 

    return AUDIOEFFECT_SUCCESS;

 

 

    // failures:

setup_failure:

 

 

    if (nId != NULL) {

        env->ReleasePrimitiveArrayCritical(jId, nId, 0);

    }

 

 

    if (lpAudioEffect) {

        delete lpAudioEffect;

    }

    env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);

 

 

    if (lpJniStorage) {

        delete lpJniStorage;

    }

    env->SetIntField(thiz, fields.fidJniData, 0);

 

 

    if (uuidStr != NULL) {

        env->ReleaseStringUTFChars(uuid, uuidStr);

    }

 

 

    if (typeStr != NULL) {

        env->ReleaseStringUTFChars(type, typeStr);

    }

 

 

    return lStatus;

}

————————-android_media_AudioEffect_native_setup—————————————

        if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {

            Log.e(TAG, "Error code " + initResult

                    + " when initializing AudioEffect.");

            switch (initResult) {

            case ERROR_BAD_VALUE:

                throw (new IllegalArgumentException("Effect type: " + type

                        + " not supported."));

            case ERROR_INVALID_OPERATION:

                throw (new UnsupportedOperationException(

                        "Effect library not loaded"));

            default:

                throw (new RuntimeException(

                        "Cannot initialize effect engine for type: " + type

                                + "Error: " + initResult));

            }

        }

        mId = id[0];

        mDescriptor = desc[0];

        synchronized (mStateLock) {

            mState = STATE_INITIALIZED;

        }

    }

——————————–AudioEffect——————————–

            assertNotNull(msg + ": could not create AudioEffect", effect);

            try {

                assertTrue(msg +": invalid effect ID", (effect.getId() != 0));

            } catch (IllegalStateException e) {

                msg = msg.concat(": AudioEffect not initialized");

                result = false;

            } finally {

                effect.release();

            }

        } catch (IllegalArgumentException e) {

            msg = msg.concat(": Effect not found: "+desc[0].name);

            result = false;

        } catch (UnsupportedOperationException e) {

            msg = msg.concat(": Effect library not loaded");

            result = false;

        }

        assertTrue(msg, result);

    }

###########################################################

 

 

&&&&&&&&&&&&&&&&&&&&&&&總結&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

在創建AudioEffect的時候:

1、如果指定瞭uuid,則會根據uuid 尋找匹配的effect lib來創建effect。

2、若沒有指定uuid而指定瞭type,則會尋找相同type中可用的effect lib。

    註意,如果session id為SESSION_OUTPUT_MIX,則優先使用auxiliary的effect。

在指定的type中沒有可用的auxiliary的effect的情況下,才會使用insert的effect。

 

effect lib都被註冊到一個列表中。

EffectsFactory中的init函數會將build-in的effect lib添加到該列表。

用戶可以調用函數EffectLoadLibrary/EffectUnloadLibrary來註冊/刪除effect lib。

 

 

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

摘自:江風的專欄

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *