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

Commit 1258c1ab authored by Andy Hung's avatar Andy Hung
Browse files

Add multiple format capability to FastMixer

Floating point data from MixerThread into FastMixer.
Multiple output format capability from FastMixer to Sink.

Change-Id: I0da17810ee71381a39a006c46faec71108d22c26
parent 798ce934
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.