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

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

Merge "Improve ResamplerBufferProvider"

parents 77a44e8d 73c02e42
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
@@ -1991,8 +1991,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;