summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorAndy Hung <hunga@google.com>2015-04-08 23:30:58 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-08 23:30:58 +0000
commit86f79e3f3bc1de7b4e4dd045de8962b8a62ab5d5 (patch)
tree222616b4bb2cb2cbfcc0d7c14581e182143e87cd /services
parent77a44e8d1f902a100500ea69a450e22889dcff31 (diff)
parent73c02e4277b399c2ec1555d32b6ad5df23bb83dc (diff)
downloadframeworks_av-86f79e3f3bc1de7b4e4dd045de8962b8a62ab5d5.zip
frameworks_av-86f79e3f3bc1de7b4e4dd045de8962b8a62ab5d5.tar.gz
frameworks_av-86f79e3f3bc1de7b4e4dd045de8962b8a62ab5d5.tar.bz2
Merge "Improve ResamplerBufferProvider"
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/RecordTracks.h8
-rw-r--r--services/audioflinger/Threads.cpp84
-rw-r--r--services/audioflinger/Threads.h33
-rw-r--r--services/audioflinger/Tracks.cpp3
4 files changed, 88 insertions, 40 deletions
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<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;
}
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 6e78b32..1566b1f 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -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;