Android原生回音消除API分析(二)音效加载分析

前面我们对AcousticEchoCanceler进行了相关的分析,在http://androidxref.com/7.1.2_r36/ 与目前学习的项目中均未实现AcousticEchoCanceler功能,因此我们接下来的分析需要假设该类库存在的情况下进行分析。我们快速的定位到AcousticEchoCanceler.setEnabled(Boolean);进行分析。依据
/frameworks/base/media/java/android/media/audiofx/AcousticEchoCanceler.java
中,setEnabled具体实现需要阅读AudioEffect类。构造函数AudioEffect(UUID type, UUID uuid, int priority, int audioSession)中对构造函数示意如下:

#type 音效引擎类型,这里传过来的是EFFECT_TYPE_AEC
#uuid 特定效果实现的唯一标识符,这里传递过来的是EFFECT_TYPE_NULL
#priority 应用程序请求的优先级控制效果引擎。同样的效果引擎可以由多个应用程序共享,此参数表示请求的应用程序需要多少效果控制参数。正常优先级为0,高于正常优先级为a正数,低于正常值为负数,这里传递过来的是0

我们粗略的看一下构造方法,其中比较核心的流程如下

{
...
//将一些参数传递给jni层
 int initResult = native_setup(new WeakReference<AudioEffect>(this), type.toString(), uuid.toString(), priority, audioSession, id,desc, ActivityThread.currentOpPackageName());
...
}

此时再来查看一下我们比较关心的setEnabled方法。

    public int setEnabled(boolean enabled) throws IllegalStateException {
        checkState("setEnabled()");
        return native_setEnabled(enabled);
    }

依据JNI相关规则我们定位到
/frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
源码中通过显式注册native_setup对应到了android_media_AudioEffect_native_setup函数,native_setEnabled对应到了android_media_AudioEffect_native_setEnabled。我们来快速过一遍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, jstring opPackageName)
{
    AudioEffectJniStorage* lpJniStorage = NULL;
    int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
    sp<AudioEffect> lpAudioEffect;
    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;
    ScopedUtfChars opPackageNameStr(env, opPackageName);
    setAudioEffect(env, thiz, 0);
    typeStr = env->GetStringUTFChars(type, NULL);
    uuidStr = env->GetStringUTFChars(uuid, NULL);
    lpJniStorage = new AudioEffectJniStorage();
    lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
    //弱引用,对象摧毁时进行垃圾回收
    lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
    //创建native AudioEffect 对象
    lpAudioEffect = new AudioEffect(typeStr,
                                    String16(opPackageNameStr.c_str()),
                                    uuidStr,
                                    priority,
                                    effectCallback,
                                    &lpJniStorage->mCallbackData,
                                    (audio_session_t) sessionId,
                                    0);
    //检查AudioEffect初始化状态
    lStatus = translateError(lpAudioEffect->initCheck());
    nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
    nId[0] = lpAudioEffect->id();
    env->ReleasePrimitiveArrayCritical(jId, nId, 0);
    //获取描述信息
    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 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
        jdescConnect = env->NewStringUTF("Pre Processing");
    } 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->SetObjectArrayElement(javadesc, 0, jdesc);
    setAudioEffect(env, thiz, lpAudioEffect);
    env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
    return (jint) AUDIOEFFECT_SUCCESS;
}

因此我们可以确定核心代码是AudioEffectJniStorageAudioEffect对象的创建。我们来看一下这几个对象的描述:

#AudioEffectJniStorage 一个辅助类,用于共享内存的访问,将调用者传递给了AudioEffect对象
#AudioEffect 音效对象

其中其主要目的是对AudioEffect对象初始化,并且调用了AudioEffect的initCheck方法获取状态。
在AudioEffect构造函数中
/frameworks/av/media/libmedia/AudioEffect.cpp

AudioEffect::AudioEffect(const char *typeStr,const String16& opPackageName,const char *uuidStr,int32_t priority,
                effect_callback_t cbf,
                void* user,
                audio_session_t sessionId,
                audio_io_handle_t io
                ): mStatus(NO_INIT), mOpPackageName(opPackageName)
                {
                ....
                mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
                ....
                }

status_t AudioEffect::set(const effect_uuid_t *type,
                const effect_uuid_t *uuid,
                int32_t priority,
                effect_callback_t cbf,
                void* user,
                audio_session_t sessionId,
                audio_io_handle_t io)
{
...
mIEffectClient = new EffectClient(this);
iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,mIEffectClient, priority, io, mSessionId, mOpPackageName, &mStatus, &mId, &enabled);
...
return mStatus;
}
status_t AudioEffect::initCheck() const
{
    return mStatus;
}

因此创建"Effect"的任务交给了audioFlinger,initCheck只是检查了创建"Effect"的状态码。
/frameworks/av/services/audioflinger/AudioFlinger.cpp

sp<IEffect> AudioFlinger::createEffect(
        effect_descriptor_t *pDesc,
        const sp<IEffectClient>& effectClient,
        int32_t priority,
        audio_io_handle_t io,
        audio_session_t sessionId,
        const String16& opPackageName,
        status_t *status,
        int *id,
        int *enabled)
{
....
    sp<EffectHandle> handle;
        ThreadBase *thread = checkRecordThread_l(io);
        handle = thread->createEffect_l(client, effectClient, priority, sessionId,
                &desc, enabled, &lStatus, pinned);
                ...
    return handle;
}

接着我们来跟踪createEffect_l代码
/frameworks/av/services/audioflinger/Threads.cpp
精简后代码如下

sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
        const sp<AudioFlinger::Client>& client,
        const sp<IEffectClient>& effectClient,
        int32_t priority,
        audio_session_t sessionId,
        effect_descriptor_t *desc,
        int *enabled,
        status_t *status,
        bool pinned)
{
    sp<EffectModule> effect;
    sp<EffectHandle> handle;
    status_t lStatus;
    sp<EffectChain> chain;

    { // scope for 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
            ALOGV("createEffect_l() new effect chain for session %d", sessionId);
            chain = new EffectChain(this, sessionId);
            addEffectChain_l(chain);
            chain->setStrategy(getStrategyForSession_l(sessionId));
        } else {
            effect = chain->getEffectFromDesc_l(desc);
        }

        if (effect == 0) {
            audio_unique_id_t id = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
            // Check CPU and memory usage
            lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
            // create a new effect module if none present in the chain
            lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned);

            effect->setDevice(mOutDevice);
            effect->setDevice(mInDevice);
            effect->setMode(mAudioFlinger->getMode());
            effect->setAudioSource(mAudioSource);
        }
        // create effect handle and connect it to effect module
        handle = new EffectHandle(effect, client, effectClient, priority);
        lStatus = handle->initCheck();
        if (lStatus == OK) {
            lStatus = effect->addHandle(handle.get());
        }
        if (enabled != NULL) {
            *enabled = (int)effect->isEnabled();
        }
    }

    *status = lStatus;
    return handle;
}

参阅网上相关资料我们需要跟踪chain->createEffect_l函数
/frameworks/av/services/audioflinger/Effects.cpp

status_t AudioFlinger::EffectChain::createEffect_l(sp<EffectModule>& effect,
                                                   ThreadBase *thread,
                                                   effect_descriptor_t *desc,
                                                   int id,
                                                   audio_session_t sessionId,
                                                   bool pinned)
{
...
    effect = new EffectModule(thread, this, desc, id, sessionId, pinned);
    status_t lStatus = effect->status();
...
    return lStatus;
}

跟踪new EffectModule
frameworks/av/services/audioflinger/Effects.cpp

AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
                                        const wp<AudioFlinger::EffectChain>& chain,
                                        effect_descriptor_t *desc,
                                        int id,
                                        audio_session_t sessionId,
                                        bool pinned)
    : mPinned(pinned),
      mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
      mDescriptor(*desc),
      // mConfig is set by configure() and not used before then
      mEffectInterface(NULL),
      mStatus(NO_INIT), mState(IDLE),
      // mMaxDisableWaitCnt is set by configure() and not used before then
      // mDisableWaitCnt is set by process() and updateState() and not used before then
      mSuspended(false),
      mAudioFlinger(thread->mAudioFlinger)
{
..
    mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
...
}

EffectCreate函数由工厂类EffectsFactory.c提供
frameworks/av/media/libeffects/factory/EffectsFactory.c

int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
{
    list_elem_t *e = gLibraryList;
    lib_entry_t *l = NULL;
    effect_descriptor_t *d = NULL;
    effect_handle_t itfe;
    effect_entry_t *fx;
    int found = 0;
    int ret;
    ret = init();
    //再配置文件中进行匹配
    ret = findEffect(NULL, uuid, &l, &d);
    if (ret < 0){
        // Sub effects are not associated with the library->effects,
        // so, findEffect will fail. Search for the effect in gSubEffectList.
        ret = findSubEffect(uuid, &l, &d);
        if (ret < 0 ) {
            goto exit;
        }
    }
    // create effect in library
    ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
    ...
    return ret;
}

这里的xxx->create_effect,在后面提到的AUDIO_EFFECT_LIBRARY_INFO_SYM结构体中进行配置。

发表评论

CAPTCHAis initialing...