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

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

Merge "Add multiple format capability to FastMixer"

parents c0008d11 1258c1ab
Loading
Loading
Loading
Loading
+33 −5
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
#include <audio_utils/format.h>
#include "AudioMixer.h"
#include "FastMixer.h"

@@ -52,7 +53,11 @@ FastMixer::FastMixer() : FastThread(),
    outputSink(NULL),
    outputSinkGen(0),
    mixer(NULL),
    mSinkBuffer(NULL),
    mSinkBufferSize(0),
    mMixerBuffer(NULL),
    mMixerBufferSize(0),
    mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
    mMixerBufferState(UNDEFINED),
    format(Format_Invalid),
    sampleRate(0),
@@ -108,7 +113,8 @@ void FastMixer::onIdle()
void FastMixer::onExit()
{
    delete mixer;
    delete[] mMixerBuffer;
    free(mMixerBuffer);
    free(mSinkBuffer);
}

bool FastMixer::isSubClassCommand(FastThreadState::Command command)
@@ -154,14 +160,23 @@ void FastMixer::onStateChange()
        // FIXME to avoid priority inversion, don't delete here
        delete mixer;
        mixer = NULL;
        delete[] mMixerBuffer;
        free(mMixerBuffer);
        mMixerBuffer = NULL;
        free(mSinkBuffer);
        mSinkBuffer = NULL;
        if (frameCount > 0 && sampleRate > 0) {
            // FIXME new may block for unbounded time at internal mutex of the heap
            //       implementation; it would be better to have normal mixer allocate for us
            //       to avoid blocking here and to prevent possible priority inversion
            mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
            mMixerBuffer = new short[frameCount * FCC_2];
            const size_t mixerFrameSize = FCC_2 * audio_bytes_per_sample(mMixerBufferFormat);
            mMixerBufferSize = mixerFrameSize * frameCount;
            (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
            const size_t sinkFrameSize = FCC_2 * audio_bytes_per_sample(format.mFormat);
            if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
                mSinkBufferSize = sinkFrameSize * frameCount;
                (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
            }
            periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
            underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
            overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
@@ -231,6 +246,10 @@ void FastMixer::onStateChange()
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
                        (void *) mMixerBuffer);
                // newly allocated track names default to full scale volume
                mixer->setParameter(
                        name,
                        AudioMixer::TRACK,
                        AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
                        (void *)(uintptr_t)fastTrack->mFormat);
                mixer->enable(name);
@@ -261,6 +280,10 @@ void FastMixer::onStateChange()
                    }
                    mixer->setParameter(name, AudioMixer::RESAMPLE,
                            AudioMixer::REMOVE, NULL);
                    mixer->setParameter(
                            name,
                            AudioMixer::TRACK,
                            AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
                            (void *)(uintptr_t)fastTrack->mFormat);
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
@@ -369,9 +392,14 @@ void FastMixer::onWork()
    //bool didFullWrite = false;    // dumpsys could display a count of partial writes
    if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
        if (mMixerBufferState == UNDEFINED) {
            memset(mMixerBuffer, 0, frameCount * FCC_2 * sizeof(short));
            memset(mMixerBuffer, 0, mMixerBufferSize);
            mMixerBufferState = ZEROED;
        }
        void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
        if (format.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
            memcpy_by_audio_format(buffer, format.mFormat, mMixerBuffer, mMixerBufferFormat,
                    frameCount * Format_channelCount(format));
        }
        // if non-NULL, then duplicate write() to this non-blocking sink
        NBAIO_Sink* teeSink;
        if ((teeSink = current->mTeeSink) != NULL) {
@@ -381,7 +409,7 @@ void FastMixer::onWork()
        //       but this code should be modified to handle both non-blocking and blocking sinks
        dumpState->mWriteSequence++;
        ATRACE_BEGIN("write");
        ssize_t framesWritten = outputSink->write(mMixerBuffer, frameCount);
        ssize_t framesWritten = outputSink->write(buffer, frameCount);
        ATRACE_END();
        dumpState->mWriteSequence++;
        if (framesWritten >= 0) {
+9 −1
Original line number Diff line number Diff line
@@ -61,7 +61,15 @@ private:
    NBAIO_Sink *outputSink;
    int outputSinkGen;
    AudioMixer* mixer;
    short *mMixerBuffer;

    // mSinkBuffer audio format is stored in format.mFormat.
    void* mSinkBuffer;                  // used for mixer output format translation
                                        // if sink format is different than mixer output.
    size_t mSinkBufferSize;
    void* mMixerBuffer;                 // mixer output buffer.
    size_t mMixerBufferSize;
    audio_format_t mMixerBufferFormat;  // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).

    enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState;
    NBAIO_Format format;
    unsigned sampleRate;
+18 −0
Original line number Diff line number Diff line
@@ -2744,9 +2744,27 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
        break;
    }
    if (initFastMixer) {
        audio_format_t fastMixerFormat;
        if (mMixerBufferEnabled && mEffectBufferEnabled) {
            fastMixerFormat = AUDIO_FORMAT_PCM_FLOAT;
        } else {
            fastMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
        }
        if (mFormat != fastMixerFormat) {
            // change our Sink format to accept our intermediate precision
            mFormat = fastMixerFormat;
            free(mSinkBuffer);
            mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat);
            const size_t sinkBufferSize = mNormalFrameCount * mFrameSize;
            (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize);
        }

        // create a MonoPipe to connect our submix to FastMixer
        NBAIO_Format format = mOutputSink->format();
        // adjust format to match that of the Fast Mixer
        format.mFormat = fastMixerFormat;
        format.mFrameSize = audio_bytes_per_sample(format.mFormat) * format.mChannelCount;

        // This pipe depth compensates for scheduling latency of the normal mixer thread.
        // When it wakes up after a maximum latency, it runs a few cycles quickly before
        // finally blocking.  Note the pipe implementation rounds up the request to a power of 2.