Android Audio代码分析21 - 创建AudioEffect对象

今天来看看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。


&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值