安卓音效AudioEffect源码剖析1——构造流程

来源:互联网 发布:到香港去网络要关闭吗 编辑:程序博客网 时间:2024/05/02 12:31
当我们写下demo代码:

PresetReverb pReverb = new PresetReverb(100, 0);

让我们看看安卓做了什么?

Java层到audioflinger的调用流程:

audioflinger service到库的创建流程:

  1. 【Java层】调用了PresetReverb的构造函数。
  2. 【Java层】PresetReverb把构造功能甩给了基类AudioEffect——frameworks/base/media/java/android/media/audiofx/PresetReverb.java
  3. 【Java层】AudioEffect使用了JNI,并把构造工作抛给了native层的native_setup。——frameworks/base/media/java/android/media/audiofx/AudioEffect.java。
  4. 【JNI层】native_setup(android_media_AudioEffect_native_setup)中调用了AudioEffect(C++)的构造代码。——framework/base/media/jni/audioeffect/android_media_AudioEffect.cpp
  5. 【native层】AudioEffect(C++)的构造代码调用了set(),set()中进一步调用了audioFlinger->createEffect()来创建音效。——frameworks/av/media/libmedia/AudioEffect.cpp
  6. 【native层】audioFlinger的客户端服务端通信略。
  7. 【native层】audioFlinger service端调用thread->createEffect_l在对应的音频线程创建音效。——frameworks\av\services\audioflinger\AudioFlinger.cpp
  8. 【native层】createEffect_l中创建了效果链,并把new EffectModule(this, chain, desc, id, sessionId)加入效果链。——frameworks/av/services/audioflinger/Threads.cpp
  9. 【native层】EffectModule的构造函数中调用了EffectFactory的EffectCreate方法来创建音效实例。——frameworks/av/services/audioflinger/Effects.cpp
  10. 【native层】EffectCreate中枚举并创建了具体的效果类。

(2)【Java层】PresetReverb把构造功能甩给了基类AudioEffect——frameworks/base/media/java/android/media/audiofx/PresetReverb.java

PresetReverb.java的构造函数如下:

public PresetReverb(int priority, int audioSession)    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {        super(EFFECT_TYPE_PRESET_REVERB, EFFECT_TYPE_NULL, priority, audioSession);    }
可见子类的构造函数没做什么事情,只是加了子类的UUID后,调用了基类的构造函数。其中EFFECT_TYPE_PRESET_REVERB和EFFECT_TYPE_NULL的定义在frameworks/base/media/java/android/media/audiofx/AudioEffect.java
public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID            .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");public static final UUID EFFECT_TYPE_NULL = UUID            .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");

3【Java层】AudioEffect使用了JNI,并把构造工作抛给了native层的native_setup。——frameworks/base/media/java/android/media/audiofx/AudioEffect.java。

public class AudioEffect {    static {        System.loadLibrary("audioeffect_jni");        native_init();    }……    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);        ……

4【JNI层】native_setup(android_media_AudioEffect_native_setup)中调用了AudioEffect(C++)的构造代码。——framework/base/media/jni/audioeffect/android_media_AudioEffect.cpp

static jintandroid_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc){    ……    // create the native AudioEffect object    lpAudioEffect = new AudioEffect(typeStr,                                    uuidStr,                                    priority,                                    effectCallback,                                    &lpJniStorage->mCallbackData,                                    sessionId,                                    0);

5【native层】AudioEffect(C++)的构造代码调用了set(),set()中进一步调用了audioFlinger->createEffect()来创建音效。——frameworks/av/media/libmedia/AudioEffect.cpp

AudioEffect::AudioEffect(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 io                )    : mStatus(NO_INIT){    mStatus = set(type, uuid, 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,                int sessionId,                audio_io_handle_t io){    sp<IEffect> iEffect;    sp<IMemory> cblk;    int enabled;        ……    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();    if (audioFlinger == 0) {        ALOGE("set(): Could not get audioflinger");        return NO_INIT;    }    if (type == NULL && uuid == NULL) {        ALOGW("Must specify at least type or uuid");        return BAD_VALUE;    }    mPriority = priority;    mCbf = cbf;    mUserData = user;    mSessionId = sessionId;    memset(&mDescriptor, 0, sizeof(effect_descriptor_t));    mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);    mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);    mIEffectClient = new EffectClient(this);    //利用audioFlinger创建音效    iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,            mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);    ……}

流程正式和AudioFlinger挂钩,并将创建特效的职责转给AudioFlinger,应用层作为一个客户端(Binder)。
Binder通信相关的流程略。

7【native层】audioFlinger service端调用thread->createEffect_l在对应的音频线程创建音效。——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,        int sessionId,        status_t *status,        int *id,        int *enabled){    status_t lStatus = NO_ERROR;    sp<EffectHandle> handle;    effect_descriptor_t desc;    ……                ThreadBase *thread = checkRecordThread_l(io);        if (thread == NULL) {            thread = checkPlaybackThread_l(io);            if (thread == NULL) {                ALOGE("createEffect() unknown output thread");                lStatus = BAD_VALUE;                goto Exit;            }        }        sp<Client> client = registerPid_l(pid);        // create effect on selected output thread(音效是在线程上的)        handle = thread->createEffect_l(client, effectClient, priority, sessionId,                &desc, enabled, &lStatus);        if (handle != 0 && id != NULL) {            *id = handle->id();        }    }……}

8【native层】createEffect_l中创建了效果链,并把new EffectModule(this,chain, desc, id, sessionId)加入效果链。——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,        int sessionId,        effect_descriptor_t *desc,        int *enabled,        status_t *status        ){    sp<EffectModule> effect;    sp<EffectHandle> handle;    status_t lStatus;    sp<EffectChain> chain;    bool chainCreated = false;    bool effectCreated = false;    bool effectRegistered = false;    ……    { // 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            ALOGV("createEffect_l() new effect chain for session %d", sessionId);            chain = new EffectChain(this, sessionId);            addEffectChain_l(chain);            chain->setStrategy(getStrategyForSession_l(sessionId));            chainCreated = true;        } else {            effect = chain->getEffectFromDesc_l(desc);        }        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;            }            effect->setOffloaded(mType == OFFLOAD, mId);            lStatus = chain->addEffect_l(effect);            if (lStatus != NO_ERROR) {                goto Exit;            }            effectCreated = true;            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 = effect->addHandle(handle.get());        if (enabled != NULL) {            *enabled = (int)effect->isEnabled();        }    }……}

9【native层】EffectModule的构造函数中调用了EffectFactory的EffectCreate方法来创建音效实例。——frameworks/av/services/audioflinger/Effects.cpp

AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,                                        const wp<AudioFlinger::EffectChain>& chain,                                        effect_descriptor_t *desc,                                        int id,                                        int sessionId)    : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX),      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){    ALOGV("Constructor %p", this);    int lStatus;    // create effect engine from effect factory    mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);    ……}

看到使用特效工厂创建,已经很近了。

10【native层】EffectCreate中枚举并创建了具体的效果类。

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();    if (ret < 0) {        ALOGW("EffectCreate() init error: %d", ret);        return ret;    }    pthread_mutex_lock(&gLibLock);    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);    if (ret != 0) {        ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);        goto exit;    }    ……}

init()从/system/etc/audio_effects.conf配置文件中初始化特效。

audio_effects.conf的结构如下:

libraries {

  ...

 downmix {

   path /system/lib/soundfx/libdownmix.so

  }

}

effects {

  ...

 downmix {

   library downmix

   uuid 93f04452-e4fe-41cc-91f9-e475b6d1d69f

  }

}

libraries指明了库的加载路径,默认是在/system/lib/soundfx/目录下。

effects包含了该系统支持的所有音效,音效所使用的库,以及音效的uuid。

有了这些信息,就可以创建音效实例了。

 

创建方法为ret =l->desc->create_effect(uuid, sessionId, ioId, &itfe);

注意:此处的itfe就是创造出来的音效实例。

0 0
原创粉丝点击