From 73c02e4277b399c2ec1555d32b6ad5df23bb83dc Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Sun, 29 Mar 2015 01:13:58 -0700 Subject: Improve ResamplerBufferProvider Change-Id: I3cc3af221ad5797ff219d75227350733afa180db --- services/audioflinger/RecordTracks.h | 8 ---- services/audioflinger/Threads.cpp | 84 ++++++++++++++++++++++++------------ services/audioflinger/Threads.h | 33 +++++++++++++- services/audioflinger/Tracks.cpp | 3 +- 4 files changed, 88 insertions(+), 40 deletions(-) (limited to 'services') diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index 5537ca2..25d6d95 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -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 diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 7e71613..c096bdd 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -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& args write(fd, result.string(), result.size()); } + +void AudioFlinger::RecordThread::ResamplerBufferProvider::reset() +{ + sp 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 = 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 = activeTrack->mThread.promote(); + sp 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; } diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 053d2e7..27bc56b 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -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 diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index b2f44f2..6560f14 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -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; -- cgit v1.1