Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70d8f430 authored by Eric Laurent's avatar Eric Laurent
Browse files

Modifications in audio effect engine state management.

- Separate the updating of effect engine state from the process call in EffectModule so that the state
of all effects in the same effect chain is updated simultaneusly before all process functions are called.
- Added a mechanism for the effect engine to continue being called for processing after receiving the disable
commands untils it considers that the framework can stop calling the process function without causing
a glitch or loosing some effect tail.
- Updated test reverb and equalizer to support this new feature

Change-Id: Icb56ae2c84c076d4dbad6cf733b1a62f823febe7
parent 281d8f99
Loading
Loading
Loading
Loading
+63 −39
Original line number Diff line number Diff line
@@ -17,8 +17,7 @@


#define LOG_TAG "AudioFlinger"
//
#define LOG_NDEBUG 0
//#define LOG_NDEBUG 0

#include <math.h>
#include <signal.h>
@@ -5085,49 +5084,69 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
    }
}

void AudioFlinger::EffectModule::process()
{
void AudioFlinger::EffectModule::updateState() {
    Mutex::Autolock _l(mLock);

    if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) {
        return;
    }

    if (mState != IDLE) {
        // do 32 bit to 16 bit conversion for auxiliary effect input buffer
        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
            AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
                                        mConfig.inputCfg.buffer.s32,
                                        mConfig.inputCfg.buffer.frameCount);
        }

        // TODO: handle effects with buffer provider
        if (mState != ACTIVE) {
    switch (mState) {
            case RESET:
    case RESTART:
        reset_l();
                mState = STARTING;
        // FALL THROUGH

    case STARTING:
        // clear auxiliary effect input buffer for next accumulation
        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
                    memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
            memset(mConfig.inputCfg.buffer.raw,
                   0,
                   mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
        }
                return;
            case STARTING:
        start_l();
        mState = ACTIVE;
        break;
    case STOPPING:
        stop_l();
        mDisableWaitCnt = mMaxDisableWaitCnt;
        mState = STOPPED;
        break;
    case STOPPED:
                stop_l();
        // mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the
        // turn off sequence.
        if (--mDisableWaitCnt == 0) {
            reset_l();
            mState = IDLE;
        }
        break;
    default: //IDLE , ACTIVE
        break;
    }
}

void AudioFlinger::EffectModule::process()
{
    Mutex::Autolock _l(mLock);

    if (mEffectInterface == NULL ||
            mConfig.inputCfg.buffer.raw == NULL ||
            mConfig.outputCfg.buffer.raw == NULL) {
        return;
    }

    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) {
        // do 32 bit to 16 bit conversion for auxiliary effect input buffer
        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
            AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
                                        mConfig.inputCfg.buffer.s32,
                                        mConfig.inputCfg.buffer.frameCount);
        }

        // do the actual processing in the effect engine
        (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
        int ret = (*mEffectInterface)->process(mEffectInterface,
                                               &mConfig.inputCfg.buffer,
                                               &mConfig.outputCfg.buffer);

        // force transition to IDLE state when engine is ready
        if (mState == STOPPED && ret == -ENODATA) {
            mDisableWaitCnt = 1;
        }

        // clear auxiliary effect input buffer for next accumulation
        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5216,6 +5235,10 @@ status_t AudioFlinger::EffectModule::configure()
    if (status == 0) {
        status = cmdStatus;
    }

    mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
            (1000 * mConfig.outputCfg.buffer.frameCount);

    return status;
}

@@ -5292,21 +5315,19 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
        switch (mState) {
        // going from disabled to enabled
        case IDLE:
            mState = RESET;
            mState = STARTING;
            break;
        case STOPPED:
            mState = RESTART;
            break;
        case STOPPING:
            mState = ACTIVE;
            break;
        case STOPPED:
            mState = STARTING;
            break;

        // going from enabled to disabled
        case RESET:
            mState = IDLE;
            break;
        case RESTART:
        case STARTING:
            mState = STOPPED;
            mState = IDLE;
            break;
        case ACTIVE:
            mState = STOPPING;
@@ -5325,7 +5346,7 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
bool AudioFlinger::EffectModule::isEnabled()
{
    switch (mState) {
    case RESET:
    case RESTART:
    case STARTING:
    case ACTIVE:
        return true;
@@ -5772,6 +5793,9 @@ void AudioFlinger::EffectChain::process_l()
    for (size_t i = 0; i < size; i++) {
        mEffects[i]->process();
    }
    for (size_t i = 0; i < size; i++) {
        mEffects[i]->updateState();
    }
    // if no track is active, input buffer must be cleared here as the mixer process
    // will not do it
    if (mSessionId > 0 && activeTracks() == 0) {
+8 −1
Original line number Diff line number Diff line
@@ -905,7 +905,7 @@ private:

        enum effect_state {
            IDLE,
            RESET,
            RESTART,
            STARTING,
            ACTIVE,
            STOPPING,
@@ -914,6 +914,7 @@ private:

        int         id() { return mId; }
        void process();
        void updateState();
        status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);

        void reset_l();
@@ -948,6 +949,9 @@ private:

    protected:

        // Maximum time allocated to effect engines to complete the turn off sequence
        static const uint32_t MAX_DISABLE_TIME_MS = 10000;

        EffectModule(const EffectModule&);
        EffectModule& operator = (const EffectModule&);

@@ -973,6 +977,9 @@ private:
        status_t mStatus;               // initialization status
        uint32_t mState;                // current activation state (effect_state)
        Vector< wp<EffectHandle> > mHandles;    // list of client handles
        uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
                                        // sending disable command.
        uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
    };

    // The EffectHandle class implements the IEffect interface. It provides resources