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

Commit 73c02e42 authored by Andy Hung's avatar Andy Hung
Browse files

Improve ResamplerBufferProvider

Change-Id: I3cc3af221ad5797ff219d75227350733afa180db
parent 97a893eb
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -67,14 +67,6 @@ private:

    bool                mOverflow;  // overflow on most recent attempt to fill client buffer


            size_t                              mRsmpInUnrel;   // unreleased frames remaining from
                                                                // most recent getNextBuffer
                                                                // for debug only

            // rolling counter that is never cleared
            int32_t                             mRsmpInFront;   // next available frame

            AudioBufferProvider::Buffer mSink;  // references client's buffer sink in shared memory

            // sync event triggering actual audio capture. Frames read before this event will
+56 −28
Original line number Diff line number Diff line
@@ -5593,6 +5593,7 @@ reacquire_wakelock:
                continue;
            }

            // TODO: This code probably should be moved to RecordTrack.
            // TODO: Update the activeTrack buffer converter in case of reconfigure.

            enum {
@@ -5609,24 +5610,14 @@ reacquire_wakelock:
                size_t framesOut = activeTrack->mSink.frameCount;
                LOG_ALWAYS_FATAL_IF((status == OK) != (framesOut > 0));

                int32_t front = activeTrack->mRsmpInFront;
                ssize_t filled = rear - front;
                // check available frames and handle overrun conditions
                // if the record track isn't draining fast enough.
                bool hasOverrun;
                size_t framesIn;

                if (filled < 0) {
                    // should not happen, but treat like a massive overrun and re-sync
                    framesIn = 0;
                    activeTrack->mRsmpInFront = rear;
                    overrun = OVERRUN_TRUE;
                } else if ((size_t) filled <= mRsmpInFrames) {
                    framesIn = (size_t) filled;
                } else {
                    // client is not keeping up with server, but give it latest data
                    framesIn = mRsmpInFrames;
                    activeTrack->mRsmpInFront = front = rear - framesIn;
                activeTrack->mResamplerBufferProvider->sync(&framesIn, &hasOverrun);
                if (hasOverrun) {
                    overrun = OVERRUN_TRUE;
                }

                if (framesOut == 0 || framesIn == 0) {
                    break;
                }
@@ -5942,8 +5933,7 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
        // was initialized to some value closer to the thread's mRsmpInFront, then the track could
        // see previously buffered data before it called start(), but with greater risk of overrun.

        recordTrack->mRsmpInFront = mRsmpInRear;
        recordTrack->mRsmpInUnrel = 0;
        recordTrack->mResamplerBufferProvider->reset();
        // clear any converter state as new data will be discontinuous
        recordTrack->mRecordBufferConverter->reset();
        recordTrack->mState = TrackBase::STARTING_2;
@@ -6121,12 +6111,52 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args
    write(fd, result.string(), result.size());
}


void AudioFlinger::RecordThread::ResamplerBufferProvider::reset()
{
    sp<ThreadBase> threadBase = mRecordTrack->mThread.promote();
    RecordThread *recordThread = (RecordThread *) threadBase.get();
    mRsmpInFront = recordThread->mRsmpInRear;
    mRsmpInUnrel = 0;
}

void AudioFlinger::RecordThread::ResamplerBufferProvider::sync(
        size_t *framesAvailable, bool *hasOverrun)
{
    sp<ThreadBase> threadBase = mRecordTrack->mThread.promote();
    RecordThread *recordThread = (RecordThread *) threadBase.get();
    const int32_t rear = recordThread->mRsmpInRear;
    const int32_t front = mRsmpInFront;
    const ssize_t filled = rear - front;

    size_t framesIn;
    bool overrun = false;
    if (filled < 0) {
        // should not happen, but treat like a massive overrun and re-sync
        framesIn = 0;
        mRsmpInFront = rear;
        overrun = true;
    } else if ((size_t) filled <= recordThread->mRsmpInFrames) {
        framesIn = (size_t) filled;
    } else {
        // client is not keeping up with server, but give it latest data
        framesIn = recordThread->mRsmpInFrames;
        mRsmpInFront = /* front = */ rear - framesIn;
        overrun = true;
    }
    if (framesAvailable != NULL) {
        *framesAvailable = framesIn;
    }
    if (hasOverrun != NULL) {
        *hasOverrun = overrun;
    }
}

// AudioBufferProvider interface
status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
{
    RecordTrack *activeTrack = mRecordTrack;
    sp<ThreadBase> threadBase = activeTrack->mThread.promote();
    sp<ThreadBase> threadBase = mRecordTrack->mThread.promote();
    if (threadBase == 0) {
        buffer->frameCount = 0;
        buffer->raw = NULL;
@@ -6134,7 +6164,7 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
    }
    RecordThread *recordThread = (RecordThread *) threadBase.get();
    int32_t rear = recordThread->mRsmpInRear;
    int32_t front = activeTrack->mRsmpInFront;
    int32_t front = mRsmpInFront;
    ssize_t filled = rear - front;
    // FIXME should not be P2 (don't want to increase latency)
    // FIXME if client not keeping up, discard
@@ -6151,17 +6181,16 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
        part1 = ask;
    }
    if (part1 == 0) {
        // Higher-level should keep mRsmpInBuffer full, and not call resampler if empty
        LOG_ALWAYS_FATAL("RecordThread::getNextBuffer() starved");
        // out of data is fine since the resampler will return a short-count.
        buffer->raw = NULL;
        buffer->frameCount = 0;
        activeTrack->mRsmpInUnrel = 0;
        mRsmpInUnrel = 0;
        return NOT_ENOUGH_DATA;
    }

    buffer->raw = recordThread->mRsmpInBuffer + front * recordThread->mChannelCount;
    buffer->frameCount = part1;
    activeTrack->mRsmpInUnrel = part1;
    mRsmpInUnrel = part1;
    return NO_ERROR;
}

@@ -6169,14 +6198,13 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer(
        AudioBufferProvider::Buffer* buffer)
{
    RecordTrack *activeTrack = mRecordTrack;
    size_t stepCount = buffer->frameCount;
    if (stepCount == 0) {
        return;
    }
    ALOG_ASSERT(stepCount <= activeTrack->mRsmpInUnrel);
    activeTrack->mRsmpInUnrel -= stepCount;
    activeTrack->mRsmpInFront += stepCount;
    ALOG_ASSERT(stepCount <= mRsmpInUnrel);
    mRsmpInUnrel -= stepCount;
    mRsmpInFront += stepCount;
    buffer->raw = NULL;
    buffer->frameCount = 0;
}
+31 −2
Original line number Diff line number Diff line
@@ -1036,17 +1036,46 @@ class RecordThread : public ThreadBase
public:

    class RecordTrack;

    /* The ResamplerBufferProvider is used to retrieve recorded input data from the
     * RecordThread.  It maintains local state on the relative position of the read
     * position of the RecordTrack compared with the RecordThread.
     */
    class ResamplerBufferProvider : public AudioBufferProvider
                        // derives from AudioBufferProvider interface for use by resampler
    {
    public:
        ResamplerBufferProvider(RecordTrack* recordTrack) : mRecordTrack(recordTrack) { }
        ResamplerBufferProvider(RecordTrack* recordTrack) :
            mRecordTrack(recordTrack),
            mRsmpInUnrel(0), mRsmpInFront(0) { }
        virtual ~ResamplerBufferProvider() { }

        // called to set the ResamplerBufferProvider to head of the RecordThread data buffer,
        // skipping any previous data read from the hal.
        virtual void reset();

        /* Synchronizes RecordTrack position with the RecordThread.
         * Calculates available frames and handle overruns if the RecordThread
         * has advanced faster than the ResamplerBufferProvider has retrieved data.
         * TODO: why not do this for every getNextBuffer?
         *
         * Parameters
         * framesAvailable:  pointer to optional output size_t to store record track
         *                   frames available.
         *      hasOverrun:  pointer to optional boolean, returns true if track has overrun.
         */

        virtual void sync(size_t *framesAvailable = NULL, bool *hasOverrun = NULL);

        // AudioBufferProvider interface
        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
        virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
    private:
        RecordTrack * const mRecordTrack;
        size_t              mRsmpInUnrel;   // unreleased frames remaining from
                                            // most recent getNextBuffer
                                            // for debug only
        int32_t             mRsmpInFront;   // next available frame
                                            // rolling counter that is never cleared
    };

    /* The RecordBufferConverter is used for format, channel, and sample rate
+1 −2
Original line number Diff line number Diff line
@@ -1990,8 +1990,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
                          ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
                  type),
        mOverflow(false),
        // See real initialization of mRsmpInFront at RecordThread::start()
        mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
        mFramesToDrop(0)
{
    if (mCblk == NULL) {
        return;