2025-03-25

 

今天來看看如何將AudioEffect與AudioTrack關聯起來。

 

 

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

    //Test case 1.7: test auxiliary effect attachement on AudioTrack

    @LargeTest

    public void test1_7AuxiliaryOnAudioTrack() throws Exception {

        boolean result = false;

        String msg = "test1_7AuxiliaryOnAudioTrack()";

 

 

        try {

            AudioTrack track = new AudioTrack(

                                        AudioManager.STREAM_MUSIC,

                                        44100,

                                        AudioFormat.CHANNEL_OUT_MONO,

                                        AudioFormat.ENCODING_PCM_16BIT,

                                        AudioTrack.getMinBufferSize(44100,

                                                                    AudioFormat.CHANNEL_OUT_MONO,

                                                                    AudioFormat.ENCODING_PCM_16BIT),

                                                                    AudioTrack.MODE_STREAM);

            assertNotNull(msg + ": could not create AudioTrack", track);

            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,

                    AudioEffect.EFFECT_TYPE_NULL,

                    0,

                    0);

 

 

            track.attachAuxEffect(effect.getId());

            track.setAuxEffectSendLevel(1.0f);

            result = true;

            effect.release();

            track.release();

        } catch (IllegalArgumentException e) {

            msg = msg.concat(": Equalizer not found");

            loge(msg, ": Equalizer not found");

        } catch (UnsupportedOperationException e) {

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

            loge(msg, ": Effect library not loaded");

        }

        assertTrue(msg, result);

    }

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

源碼路徑:

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

 

 

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

    //Test case 1.7: test auxiliary effect attachement on AudioTrack

    @LargeTest

    public void test1_7AuxiliaryOnAudioTrack() throws Exception {

        boolean result = false;

        String msg = "test1_7AuxiliaryOnAudioTrack()";

 

 

        try {

            AudioTrack track = new AudioTrack(

                                        AudioManager.STREAM_MUSIC,

                                        44100,

                                        AudioFormat.CHANNEL_OUT_MONO,

                                        AudioFormat.ENCODING_PCM_16BIT,

                                        AudioTrack.getMinBufferSize(44100,

                                                                    AudioFormat.CHANNEL_OUT_MONO,

                                                                    AudioFormat.ENCODING_PCM_16BIT),

                                                                    AudioTrack.MODE_STREAM);

            assertNotNull(msg + ": could not create AudioTrack", track);

            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,

                    AudioEffect.EFFECT_TYPE_NULL,

                    0,

                    0);

 

 

// 此處getId獲取的是調用JNI接口native_setup時得到的

            track.attachAuxEffect(effect.getId());

+++++++++++++++++++++++++++++attachAuxEffect+++++++++++++++++++++++++++++++++++

    /**

     * Attaches an auxiliary effect to the audio track. A typical auxiliary

     * effect is a reverberation effect which can be applied on any sound source

     * that directs a certain amount of its energy to this effect. This amount

     * is defined by setAuxEffectSendLevel().

     * {@see #setAuxEffectSendLevel(float)}.

     * <p>After creating an auxiliary effect (e.g.

     * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with

     * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling

     * this method to attach the audio track to the effect.

     * <p>To detach the effect from the audio track, call this method with a

     * null effect id.

     *

     * @param effectId system wide unique id of the effect to attach

     * @return error code or success, see {@link #SUCCESS},

     *    {@link #ERROR_INVALID_OPERATION}, {@link #ERROR_BAD_VALUE}

     */

    public int attachAuxEffect(int effectId) {

        if (mState != STATE_INITIALIZED) {

            return ERROR_INVALID_OPERATION;

        }

        return native_attachAuxEffect(effectId);

++++++++++++++++++++++++++++android_media_AudioTrack_attachAuxEffect++++++++++++++++++++++++++++++++++++

static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env,  jobject thiz,

        jint effectId) {

 

 

    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(

                thiz, javaAudioTrackFields.nativeTrackInJavaObj);

 

 

    if (lpTrack) {

        return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );

++++++++++++++++++++++++++++++AudioTrack::attachAuxEffect++++++++++++++++++++++++++++++++++

status_t AudioTrack::attachAuxEffect(int effectId)

{

    LOGV("attachAuxEffect(%d)", effectId);

// mAudioTrack在函數AudioTrack::createTrack中被賦值,其最終指向的其實是一個TrackHandle對象

    status_t status = mAudioTrack->attachAuxEffect(effectId);

++++++++++++++++++++++++++++++AudioFlinger::TrackHandle::attachAuxEffect++++++++++++++++++++++++++++++++++

status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId)

{

    return mTrack->attachAuxEffect(EffectId);

++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::attachAuxEffect++++++++++++++++++++++++++++++++++

status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)

{

    status_t status = DEAD_OBJECT;

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

    if (thread != 0) {

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

       status = playbackThread->attachAuxEffect(this, EffectId);

++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::attachAuxEffect++++++++++++++++++++++++++++++++++

status_t AudioFlinger::PlaybackThread::attachAuxEffect(

        const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)

{

    Mutex::Autolock _l(mLock);

    return attachAuxEffect_l(track, EffectId);

+++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::attachAuxEffect_l+++++++++++++++++++++++++++++++++++

status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(

        const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)

{

    status_t status = NO_ERROR;

 

 

// 如果EffectId為0,其實是清楚effect

    if (EffectId == 0) {

        track->setAuxBuffer(0, NULL);

+++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::setAuxBuffer+++++++++++++++++++++++++++++++++++

void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer)

{

// 函數AudioFlinger::PlaybackThread::detachAuxEffect_l中調用瞭函數AudioFlinger::PlaybackThread::Track::auxEffectId來得到mAuxEffectId

    mAuxEffectId = EffectId;

// 函數AudioFlinger::MixerThread::prepareTracks_l中會調用函數AudioFlinger::PlaybackThread::Track::auxBuffer獲取mAuxBuffer

//            mAudioMixer->setParameter(

//                AudioMixer::TRACK,

//                AudioMixer::AUX_BUFFER, (void *)track->auxBuffer());

    mAuxBuffer = buffer;

}

—————————–AudioFlinger::PlaybackThread::Track::setAuxBuffer———————————–

    } else {

        // Auxiliary effects are always in audio session AudioSystem::SESSION_OUTPUT_MIX

        sp<EffectModule> effect = getEffect_l(AudioSystem::SESSION_OUTPUT_MIX, EffectId);

+++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::getEffect_l+++++++++++++++++++++++++++++++++++

sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)

{

    sp<EffectModule> effect;

 

 

// 先得到chain

    sp<EffectChain> chain = getEffectChain_l(sessionId);

++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::getEffectChain_l++++++++++++++++++++++++++++++++++++

sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId)

{

    sp<EffectChain> chain;

 

 

    size_t size = mEffectChains.size();

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

        if (mEffectChains[i]->sessionId() == sessionId) {

// 函數AudioFlinger::PlaybackThread::addEffectChain_l會向mEffectChains添加成員

// 函數AudioFlinger::PlaybackThread::createEffect_l和AudioFlinger::PlaybackThread::addEffect_l中,

// 會判斷指定session Id對應的effect chain是否存在,若不存在,創建一個,並調用mEffectChains添加到mEffectChains中

            chain = mEffectChains[i];

            break;

        }

    }

    return chain;

}

—————————-AudioFlinger::PlaybackThread::getEffectChain_l————————————

    if (chain != 0) {

// 再根據effect Id從chain上得到effect

        effect = chain->getEffectFromId_l(effectId);

+++++++++++++++++++++++++++AudioFlinger::EffectChain::getEffectFromId_l+++++++++++++++++++++++++++++++++++++

// getEffectFromId_l() must be called with PlaybackThread::mLock held

sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id)

{

    sp<EffectModule> effect;

    size_t size = mEffects.size();

 

 

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

        // by convention, return first effect if id provided is 0 (0 is never a valid id)

        if (id == 0 || mEffects[i]->id() == id) {

// 函數AudioFlinger::EffectChain::addEffect_l會向mEffects中添加effect

// 函數AudioFlinger::PlaybackThread::createEffect_l和AudioFlinger::PlaybackThread::addEffect_l中,

// 會調用函數AudioFlinger::EffectChain::addEffect_l

            effect = mEffects[i];

            break;

        }

    }

    return effect;

}

—————————AudioFlinger::EffectChain::getEffectFromId_l————————————-

    }

    return effect;

}

—————————–AudioFlinger::PlaybackThread::getEffect_l———————————–

        if (effect != 0) {

            if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {

                track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer());

            } else {

                status = INVALID_OPERATION;

            }

        } else {

            status = BAD_VALUE;

        }

    }

    return status;

}

—————————–AudioFlinger::PlaybackThread::attachAuxEffect_l———————————–

}

——————————AudioFlinger::PlaybackThread::attachAuxEffect———————————-

    }

    return status;

}

——————————AudioFlinger::PlaybackThread::Track::attachAuxEffect———————————-

}

——————————AudioFlinger::TrackHandle::attachAuxEffect———————————-

    if (status == NO_ERROR) {

        mAuxEffectId = effectId;

    }

    return status;

}

——————————AudioTrack::attachAuxEffect———————————-

    } else {

        jniThrowException(env, "java/lang/IllegalStateException",

            "Unable to retrieve AudioTrack pointer for attachAuxEffect()");

        return AUDIOTRACK_ERROR;

    }

}

—————————-android_media_AudioTrack_attachAuxEffect————————————

    }

—————————–attachAuxEffect———————————–

            track.setAuxEffectSendLevel(1.0f);

+++++++++++++++++++++++++++++++setAuxEffectSendLevel+++++++++++++++++++++++++++++++++

    /**

     * Sets the send level of the audio track to the attached auxiliary effect

     * {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.

     * <p>By default the send level is 0, so even if an effect is attached to the player

     * this method must be called for the effect to be applied.

     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled

     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,

     * so an appropriate conversion from linear UI input x to level is:

     * x == 0 -> level = 0

     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)

     *

     * @param level send level scalar

     * @return error code or success, see {@link #SUCCESS},

     *    {@link #ERROR_INVALID_OPERATION}

     */

    public int setAuxEffectSendLevel(float level) {

        if (mState != STATE_INITIALIZED) {

            return ERROR_INVALID_OPERATION;

        }

        // clamp the level

        if (level < getMinVolume()) {

            level = getMinVolume();

        }

        if (level > getMaxVolume()) {

            level = getMaxVolume();

        }

        native_setAuxEffectSendLevel(level);

++++++++++++++++++++++++++++++android_media_AudioTrack_setAuxEffectSendLevel++++++++++++++++++++++++++++++++++

static void

android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )

{

    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(

        thiz, javaAudioTrackFields.nativeTrackInJavaObj);

    if (lpTrack == NULL ) {

        jniThrowException(env, "java/lang/IllegalStateException",

            "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");

        return;

    }

 

 

    lpTrack->setAuxEffectSendLevel(level);

+++++++++++++++++++++++++++++AudioTrack::setAuxEffectSendLevel+++++++++++++++++++++++++++++++++++

status_t AudioTrack::setAuxEffectSendLevel(float level)

{

    LOGV("setAuxEffectSendLevel(%f)", level);

    if (level > 1.0f) {

        return BAD_VALUE;

    }

 

 

    mSendLevel = level;

 

 

// 函數AudioFlinger::MixerThread::prepareTracks_l中有使用mCblk->sendLevel

// va = (uint32_t)(v * cblk->sendLevel);

// aux = int16_t(va);

// mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux);

    mCblk->sendLevel = uint16_t(level * 0x1000);

 

 

    return NO_ERROR;

}

—————————–AudioTrack::setAuxEffectSendLevel———————————–

}

——————————android_media_AudioTrack_setAuxEffectSendLevel———————————-

        return SUCCESS;

    }

——————————-setAuxEffectSendLevel———————————

            result = true;

            effect.release();

            track.release();

        } catch (IllegalArgumentException e) {

            msg = msg.concat(": Equalizer not found");

            loge(msg, ": Equalizer not found");

        } catch (UnsupportedOperationException e) {

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

            loge(msg, ": Effect library not loaded");

        }

        assertTrue(msg, result);

    }

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

 

 

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

attachAuxEffect最終會將effect 的in buffer賦值給track對象的auxBuffer。

setAuxEffectSendLevel會將send level保存到audio_track_cblk_t對象中。

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

摘自:江風的專欄

發佈留言

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