summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-05-18 10:47:28 -0700
committerGlenn Kasten <gkasten@google.com>2012-05-18 11:44:27 -0700
commit6d8aabe8a3be1ac0789d00b82c3ca8b81381f5ab (patch)
tree1f621b7f3f61ede29474f1d2c3802ecffa1df4c7 /services
parent874a897f09dc7b06679bb273506d7e0fa0152220 (diff)
downloadframeworks_av-6d8aabe8a3be1ac0789d00b82c3ca8b81381f5ab.zip
frameworks_av-6d8aabe8a3be1ac0789d00b82c3ca8b81381f5ab.tar.gz
frameworks_av-6d8aabe8a3be1ac0789d00b82c3ca8b81381f5ab.tar.bz2
Add throttle to have pipe fill at more stable rate
Change-Id: Ibff9ab62764e2acd04518a4a00e25f19e28aff4a
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/MonoPipe.cpp74
-rw-r--r--services/audioflinger/MonoPipe.h1
2 files changed, 58 insertions, 17 deletions
diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp
index b0ddf83..fd16e92 100644
--- a/services/audioflinger/MonoPipe.cpp
+++ b/services/audioflinger/MonoPipe.cpp
@@ -33,16 +33,6 @@ MonoPipe::MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock) :
mRear(0),
mWriteCanBlock(writeCanBlock)
{
- if (writeCanBlock) {
- // compute sleep time to be about 2/3 of a full pipe;
- // this gives a balance between risk of underrun vs. too-frequent wakeups
- mSleep.tv_sec = 0;
- uint64_t ns = mMaxFrames * (666666667 / Format_sampleRate(format));
- if (ns > 999999999) {
- ns = 999999999;
- }
- mSleep.tv_nsec = ns;
- }
}
MonoPipe::~MonoPipe()
@@ -62,13 +52,13 @@ ssize_t MonoPipe::availableToWrite() const
ssize_t MonoPipe::write(const void *buffer, size_t count)
{
- // count == 0 is unlikely and not worth checking for explicitly; will be handled automatically
if (CC_UNLIKELY(!mNegotiated)) {
return NEGOTIATE;
}
size_t totalFramesWritten = 0;
- for (;;) {
- size_t written = availableToWrite();
+ while (count > 0) {
+ size_t avail = availableToWrite();
+ size_t written = avail;
if (CC_LIKELY(written > count)) {
written = count;
}
@@ -88,12 +78,64 @@ ssize_t MonoPipe::write(const void *buffer, size_t count)
android_atomic_release_store(written + mRear, &mRear);
totalFramesWritten += written;
}
- if ((count -= written) == 0 || !mWriteCanBlock) {
+ if (!mWriteCanBlock) {
break;
}
+ count -= written;
buffer = (char *) buffer + (written << mBitShift);
- // simulate blocking I/O by sleeping
- nanosleep(&mSleep, NULL);
+ // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
+ // The throttle tries to keep the pipe about 5/8 full on average, with a slight jitter.
+ uint64_t ns;
+ enum {
+ THROTTLE_VERY_FAST, // pipe is (nearly) empty, fill quickly
+ THROTTLE_FAST, // pipe is normal, fill at slightly faster rate
+ THROTTLE_NOMINAL, // pipe is normal, fill at nominal rate
+ THROTTLE_SLOW, // pipe is normal, fill at slightly slower rate
+ THROTTLE_VERY_SLOW, // pipe is (nearly) full, fill slowly
+ } throttle;
+ avail -= written;
+ // FIXME cache these values to avoid re-computation
+ if (avail >= (mMaxFrames * 3) / 4) {
+ throttle = THROTTLE_VERY_FAST;
+ } else if (avail >= mMaxFrames / 2) {
+ throttle = THROTTLE_FAST;
+ } else if (avail >= (mMaxFrames * 3) / 8) {
+ throttle = THROTTLE_NOMINAL;
+ } else if (avail >= mMaxFrames / 4) {
+ throttle = THROTTLE_SLOW;
+ } else {
+ throttle = THROTTLE_VERY_SLOW;
+ }
+ if (written > 0) {
+ // FIXME cache these values also
+ switch (throttle) {
+ case THROTTLE_VERY_FAST:
+ default:
+ ns = written * ( 500000000 / Format_sampleRate(mFormat));
+ break;
+ case THROTTLE_FAST:
+ ns = written * ( 750000000 / Format_sampleRate(mFormat));
+ break;
+ case THROTTLE_NOMINAL:
+ ns = written * (1000000000 / Format_sampleRate(mFormat));
+ break;
+ case THROTTLE_SLOW:
+ ns = written * (1100000000 / Format_sampleRate(mFormat));
+ break;
+ case THROTTLE_VERY_SLOW:
+ ns = written * (1250000000 / Format_sampleRate(mFormat));
+ break;
+ }
+ } else {
+ ns = mMaxFrames * (250000000 / Format_sampleRate(mFormat));
+ }
+ if (ns > 999999999) {
+ ns = 999999999;
+ }
+ struct timespec sleep;
+ sleep.tv_sec = 0;
+ sleep.tv_nsec = ns;
+ nanosleep(&sleep, NULL);
}
mFramesWritten += totalFramesWritten;
return totalFramesWritten;
diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h
index 45e6bb4..1f56e54 100644
--- a/services/audioflinger/MonoPipe.h
+++ b/services/audioflinger/MonoPipe.h
@@ -67,7 +67,6 @@ private:
volatile int32_t mRear; // written by writer with android_atomic_release_store,
// read by reader with android_atomic_acquire_load
const bool mWriteCanBlock; // whether write() should block if the pipe is full
- struct timespec mSleep; // time to sleep if blocking is enabled and the pipe is full
};
} // namespace android