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

Commit 00133aee authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Add mEffectBuffer to AudioFlinger"

parents 1574f41d 98ef978d
Loading
Loading
Loading
Loading
+75 −21
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <audio_effects/effect_ns.h>
#include <audio_effects/effect_aec.h>
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>

// NBAIO implementations
#include <media/nbaio/AudioStreamOutSink.h>
@@ -820,6 +821,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
        goto Exit;
    }

    // Reject any effect on Direct output threads for now, since the format of
    // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo).
    if (mType == DIRECT) {
        ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s",
                desc->name, mName);
        lStatus = BAD_VALUE;
        goto Exit;
    }

    // Allow global effects only on offloaded and mixer threads
    if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
        switch (mType) {
@@ -1072,6 +1082,11 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
        mMixerBufferSize(0),
        mMixerBufferFormat(AUDIO_FORMAT_INVALID),
        mMixerBufferValid(false),
        mEffectBufferEnabled(false),
        mEffectBuffer(NULL),
        mEffectBufferSize(0),
        mEffectBufferFormat(AUDIO_FORMAT_INVALID),
        mEffectBufferValid(false),
        mSuspended(0), mBytesWritten(0),
        mActiveTracksGeneration(0),
        // mStreamTypes[] initialized in constructor body
@@ -1132,6 +1147,7 @@ AudioFlinger::PlaybackThread::~PlaybackThread()
    mAudioFlinger->unregisterWriter(mNBLogWriter);
    delete[] mSinkBuffer;
    free(mMixerBuffer);
    free(mEffectBuffer);
}

void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
@@ -1218,6 +1234,7 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>&
    fdprintf(fd, "  Suspend count: %d\n", mSuspended);
    fdprintf(fd, "  Sink buffer : %p\n", mSinkBuffer);
    fdprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
    fdprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
    fdprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);

    dumpBase(fd, args);
@@ -1781,6 +1798,14 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
                * audio_bytes_per_sample(mMixerBufferFormat);
        (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
    }
    free(mEffectBuffer);
    mEffectBuffer = NULL;
    if (mEffectBufferEnabled) {
        mEffectBufferFormat = AUDIO_FORMAT_PCM_16_BIT; // Note: Effects support 16b only
        mEffectBufferSize = mNormalFrameCount * mChannelCount
                * audio_bytes_per_sample(mEffectBufferFormat);
        (void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize);
    }

    // force reconfiguration of effect chains and engines to take new buffer size and audio
    // parameters into account
@@ -2086,7 +2111,8 @@ void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamTy
status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
{
    int session = chain->sessionId();
    int16_t *buffer = mSinkBuffer;
    int16_t *buffer = mEffectBufferEnabled
            ? reinterpret_cast<int16_t*>(mEffectBuffer) : mSinkBuffer;
    bool ownsBuffer = false;

    ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
@@ -2126,7 +2152,8 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
    }

    chain->setInBuffer(buffer, ownsBuffer);
    chain->setOutBuffer(mSinkBuffer);
    chain->setOutBuffer(mEffectBufferEnabled
            ? reinterpret_cast<int16_t*>(mEffectBuffer) : mSinkBuffer);
    // Effect chain for session AUDIO_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 AUDIO_SESSION_OUTPUT_MIX is inserted before
@@ -2373,23 +2400,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
            if (mMixerStatus == MIXER_TRACKS_READY) {
                // threadLoop_mix() sets mCurrentWriteLength
                threadLoop_mix();

                // Merge mMixerBuffer data into mSinkBuffer
                // This is done pre-effects computation; if effects change to
                // support higher precision, this needs to move.
                //
                // mMixerBufferValid is only set true by MixerThread::prepareTracks_l().
                if (mMixerBufferValid) {
                    if (mMixerBufferFormat == AUDIO_FORMAT_PCM_FLOAT) {
                        memcpy_to_i16_from_float(mSinkBuffer,
                                reinterpret_cast<float*>(mMixerBuffer),
                                mNormalFrameCount * mChannelCount);
                    } else { // mMixerBufferFormat == AUDIO_FORMAT_PCM_16_BIT
                        memcpy(mSinkBuffer,
                                mMixerBuffer,
                                mNormalFrameCount * mChannelCount * sizeof(int16_t));
                    }
                }
            } else if ((mMixerStatus != MIXER_DRAIN_TRACK)
                        && (mMixerStatus != MIXER_DRAIN_ALL)) {
                // threadLoop_sleepTime sets sleepTime to 0 if data
@@ -2399,6 +2409,24 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                    mCurrentWriteLength = mSinkBufferSize;
                }
            }
            // Either threadLoop_mix() or threadLoop_sleepTime() should have set
            // mMixerBuffer with data if mMixerBufferValid is true and sleepTime == 0.
            // Merge mMixerBuffer data into mEffectBuffer (if any effects are valid)
            // or mSinkBuffer (if there are no effects).
            //
            // This is done pre-effects computation; if effects change to
            // support higher precision, this needs to move.
            //
            // mMixerBufferValid is only set true by MixerThread::prepareTracks_l().
            // TODO use sleepTime == 0 as an additional condition.
            if (mMixerBufferValid) {
                void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
                audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;

                memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
                        mNormalFrameCount * mChannelCount);
            }

            mBytesRemaining = mCurrentWriteLength;
            if (isSuspended()) {
                sleepTime = suspendSleepTimeUs();
@@ -2424,6 +2452,16 @@ bool AudioFlinger::PlaybackThread::threadLoop()
            }
        }

        // Only if the Effects buffer is enabled and there is data in the
        // Effects buffer (buffer valid), we need to
        // copy into the sink buffer.
        // TODO use sleepTime == 0 as an additional condition.
        if (mEffectBufferValid) {
            //ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
            memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
                    mNormalFrameCount * mChannelCount);
        }

        // enable changes in effect chain
        unlockEffectChains(effectChains);

@@ -2896,7 +2934,13 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime()
            sleepTime = idleSleepTime;
        }
    } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {
        // clear out mMixerBuffer or mSinkBuffer, to ensure buffers are cleared
        // before effects processing or output.
        if (mMixerBufferValid) {
            memset(mMixerBuffer, 0, mMixerBufferSize);
        } else {
            memset(mSinkBuffer, 0, mSinkBufferSize);
        }
        sleepTime = 0;
        ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED),
                "anticipated start");
@@ -2944,6 +2988,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
    }

    mMixerBufferValid = false;  // mMixerBuffer has no valid data until appropriate tracks found.
    mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.

    for (size_t i=0 ; i<count ; i++) {
        const sp<Track> t = mActiveTracks[i].promote();
@@ -3151,6 +3196,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
            chain.clear();
            if (track->mainBuffer() != mSinkBuffer &&
                    track->mainBuffer() != mMixerBuffer) {
                if (mEffectBufferEnabled) {
                    mEffectBufferValid = true; // Later can set directly.
                }
                chain = getEffectChain_l(track->sessionId());
                // Delegate volume control to effect in track effect chain if needed
                if (chain != 0) {
@@ -3279,7 +3327,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
            /*
             * Select the appropriate output buffer for the track.
             *
             * For tracks with effects, only mSinkBuffer can be used (at this time).
             * Tracks with effects go into their own effects chain buffer
             * and from there into either mEffectBuffer or mSinkBuffer.
             *
             * Other tracks can use mMixerBuffer for higher precision
             * channel accumulation.  If this buffer is enabled
@@ -3441,6 +3490,11 @@ track_is_ready: ;
            // must imply MIXER_TRACKS_READY.
            // Later, we may clear buffers regardless, and skip much of this logic.
        }
        // TODO - either mEffectBuffer or mSinkBuffer needs to be cleared.
        if (mEffectBufferValid) {
            memset(mEffectBuffer, 0, mEffectBufferSize);
        }
        // FIXME as a performance optimization, should remember previous zero status
        memset(mSinkBuffer, 0, mNormalFrameCount * mChannelCount * sizeof(int16_t));
    }

+35 −0
Original line number Diff line number Diff line
@@ -484,6 +484,15 @@ protected:

    int16_t*                        mSinkBuffer;         // frame size aligned sink buffer

    // TODO:
    // Rearrange the buffer info into a struct/class with
    // clear, copy, construction, destruction methods.
    //
    // mSinkBuffer also has associated with it:
    //
    // mSinkBufferSize: Sink Buffer Size
    // mFormat: Sink Buffer Format

    // Mixer Buffer (mMixerBuffer*)
    //
    // In the case of floating point or multichannel data, which is not in the
@@ -507,6 +516,32 @@ protected:
    // when mMixerBuffer contains valid data after mixing.
    bool                            mMixerBufferValid;

    // Effects Buffer (mEffectsBuffer*)
    //
    // In the case of effects data, which is not in the sink format,
    // it is required to accumulate in a different buffer before data conversion
    // to the sink buffer.

    // Set to "true" to enable the Effects Buffer otherwise effects output goes to sink buffer.
    bool                            mEffectBufferEnabled;

    // Storage, 32 byte aligned (may make this alignment a requirement later).
    // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
    void*                           mEffectBuffer;

    // Size of mEffectsBuffer in bytes: mNormalFrameCount * #channels * sampsize.
    size_t                          mEffectBufferSize;

    // The audio format of mEffectsBuffer. Set to AUDIO_FORMAT_PCM_16_BIT only.
    audio_format_t                  mEffectBufferFormat;

    // An internal flag set to true by MixerThread::prepareTracks_l()
    // when mEffectsBuffer contains valid data after mixing.
    //
    // When this is set, all mixer data is routed into the effects buffer
    // for any processing (including output processing).
    bool                            mEffectBufferValid;

    // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
    // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
    // concurrent use of both of them, so Audio Policy Service suspends one of the threads to