summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-06-07 10:17:54 -0700
committerGlenn Kasten <gkasten@google.com>2012-06-08 10:09:22 -0700
commit28ed2f93324988767b5658eba7c1fa781a275183 (patch)
tree07ba39f61d41aa6ff2af76dc2c9122a102c92059
parenta4f7e0e9a0e92a063f1b3a08988cf46e2cf1fa94 (diff)
downloadframeworks_av-28ed2f93324988767b5658eba7c1fa781a275183.zip
frameworks_av-28ed2f93324988767b5658eba7c1fa781a275183.tar.gz
frameworks_av-28ed2f93324988767b5658eba7c1fa781a275183.tar.bz2
Reduce underruns in screen off, esp. with EQ
Add MonoPipe APIs to specify setpoint. Use screen state to configure pipe setpoint. Fix a long-standing bug where pipe sleep time was excessive, which interacted poorly with governor and low clock frequencies. Now it deducts the elapsed time since last write(), which was significant when there was EQ and low clock frequency. Bug: 6618373 Change-Id: I6f3b0072c2244aeb033ef0795ad164491a164ff5
-rw-r--r--include/media/AudioParameter.h2
-rw-r--r--media/libmedia/AudioParameter.cpp1
-rw-r--r--services/audioflinger/Android.mk3
-rw-r--r--services/audioflinger/AudioFlinger.cpp23
-rw-r--r--services/audioflinger/AudioFlinger.h1
-rw-r--r--services/audioflinger/MonoPipe.cpp71
-rw-r--r--services/audioflinger/MonoPipe.h7
7 files changed, 91 insertions, 17 deletions
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index 8cb2fa7..891bc4b 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -40,12 +40,14 @@ public:
// keyFrameCount: to change audio output frame count, value is an int
// keyInputSource: to change audio input source, value is an int in audio_source_t
// (defined in media/mediarecorder.h)
+ // keyScreenState: either "on" or "off"
static const char * const keyRouting;
static const char * const keySamplingRate;
static const char * const keyFormat;
static const char * const keyChannels;
static const char * const keyFrameCount;
static const char * const keyInputSource;
+ static const char * const keyScreenState;
String8 toString();
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 9766ee6..e3fea77 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -31,6 +31,7 @@ const char * const AudioParameter::keyFormat = AUDIO_PARAMETER_STREAM_FORMAT;
const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS;
const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
+const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
AudioParameter::AudioParameter(const String8& keyValuePairs)
{
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 14b7fc1..ee843aa 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -30,6 +30,9 @@ LOCAL_SRC_FILES := \
#LOCAL_C_INCLUDES += path/to/libsndfile/src
#LOCAL_STATIC_LIBRARIES += libsndfile
+# uncomment for systrace
+# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
+
LOCAL_MODULE := libnbaio
include $(BUILD_STATIC_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 67dbfe9..be59ca0 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -164,6 +164,9 @@ static const enum {
// up large writes into smaller ones, and the wrapper would need to deal with scheduler.
} kUseFastMixer = FastMixer_Static;
+static uint32_t gScreenState; // incremented by 2 when screen state changes, bit 0 == 1 means "off"
+ // AudioFlinger::setParameters() updates, other threads read w/o lock
+
// ----------------------------------------------------------------------------
#ifdef ADD_BATTERY_DATA
@@ -889,6 +892,13 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
mBtNrecIsOff = btNrecIsOff;
}
}
+ String8 screenState;
+ if (param.get(String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) {
+ bool isOff = screenState == "off";
+ if (isOff != (gScreenState & 1)) {
+ gScreenState = ((gScreenState & ~1) + 2) | isOff;
+ }
+ }
return final_result;
}
@@ -1501,6 +1511,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
mMixerStatus(MIXER_IDLE),
mMixerStatusIgnoringFastTracks(MIXER_IDLE),
standbyDelay(AudioFlinger::mStandbyTimeInNsecs),
+ mScreenState(gScreenState),
// index 0 is reserved for normal mixer's submix
mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1)
{
@@ -2224,6 +2235,8 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
size_t numCounterOffers = 0;
ssize_t index = monoPipe->negotiate(offers, 1, NULL, numCounterOffers);
ALOG_ASSERT(index == 0);
+ monoPipe->setAvgFrames((mScreenState & 1) ?
+ (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
mPipeSink = monoPipe;
#ifdef TEE_SINK_FRAMES
@@ -2686,6 +2699,16 @@ void AudioFlinger::PlaybackThread::threadLoop_write()
#if defined(ATRACE_TAG) && (ATRACE_TAG != ATRACE_TAG_NEVER)
Tracer::traceBegin(ATRACE_TAG, "write");
#endif
+ // update the setpoint when gScreenState changes
+ uint32_t screenState = gScreenState;
+ if (screenState != mScreenState) {
+ mScreenState = screenState;
+ MonoPipe *pipe = (MonoPipe *)mPipeSink.get();
+ if (pipe != NULL) {
+ pipe->setAvgFrames((mScreenState & 1) ?
+ (pipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
+ }
+ }
ssize_t framesWritten = mNormalSink->write(mMixBuffer, count);
#if defined(ATRACE_TAG) && (ATRACE_TAG != ATRACE_TAG_NEVER)
Tracer::traceEnd(ATRACE_TAG);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1c44f2f..677d466 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1119,6 +1119,7 @@ public:
// For dumpsys
sp<NBAIO_Sink> mTeeSink;
sp<NBAIO_Source> mTeeSource;
+ uint32_t mScreenState; // cached copy of gScreenState
public:
virtual bool hasFastMixer() const = 0;
virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const
diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp
index 6efb8b1..f3fc19a 100644
--- a/services/audioflinger/MonoPipe.cpp
+++ b/services/audioflinger/MonoPipe.cpp
@@ -20,6 +20,7 @@
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <utils/Log.h>
+#include <utils/Trace.h>
#include "MonoPipe.h"
#include "roundup.h"
@@ -32,6 +33,9 @@ MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
mFront(0),
mRear(0),
+ mWriteTsValid(false),
+ // mWriteTs
+ mSetpoint((reqFrames * 11) / 16),
mWriteCanBlock(writeCanBlock)
{
}
@@ -87,40 +91,75 @@ ssize_t MonoPipe::write(const void *buffer, size_t count)
count -= written;
buffer = (char *) buffer + (written << mBitShift);
// Simulate blocking I/O by sleeping at different rates, depending on a throttle.
- // The throttle tries to keep the pipe about 11/16 full on average, with a slight jitter.
+ // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
uint32_t ns;
if (written > 0) {
size_t filled = (mMaxFrames - avail) + written;
// FIXME cache these values to avoid re-computation
- if (filled <= mReqFrames / 4) {
+ if (filled <= mSetpoint / 2) {
// pipe is (nearly) empty, fill quickly
ns = written * ( 500000000 / Format_sampleRate(mFormat));
- } else if (filled <= mReqFrames / 2) {
- // pipe is normal, fill at slightly faster rate
+ } else if (filled <= (mSetpoint * 3) / 4) {
+ // pipe is below setpoint, fill at slightly faster rate
ns = written * ( 750000000 / Format_sampleRate(mFormat));
- } else if (filled <= (mReqFrames * 5) / 8) {
- // pipe is normal, fill at nominal rate
+ } else if (filled <= (mSetpoint * 5) / 4) {
+ // pipe is at setpoint, fill at nominal rate
ns = written * (1000000000 / Format_sampleRate(mFormat));
- } else if (filled <= (mReqFrames * 3) / 4) {
- // pipe is normal, fill at slightly slower rate
- ns = written * (1100000000 / Format_sampleRate(mFormat));
+ } else if (filled <= (mSetpoint * 3) / 2) {
+ // pipe is above setpoint, fill at slightly slower rate
+ ns = written * (1150000000 / Format_sampleRate(mFormat));
+ } else if (filled <= (mSetpoint * 7) / 4) {
+ // pipe is overflowing, fill slowly
+ ns = written * (1350000000 / Format_sampleRate(mFormat));
} else {
- // pipe is (nearly) full, fill slowly
- ns = written * (1250000000 / Format_sampleRate(mFormat));
+ // pipe is severely overflowing
+ ns = written * (1750000000 / Format_sampleRate(mFormat));
}
} else {
- ns = mReqFrames * (250000000 / Format_sampleRate(mFormat));
+ ns = count * (1350000000 / Format_sampleRate(mFormat));
}
if (ns > 999999999) {
ns = 999999999;
}
- struct timespec sleep;
- sleep.tv_sec = 0;
- sleep.tv_nsec = ns;
- nanosleep(&sleep, NULL);
+ struct timespec nowTs;
+ bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs);
+ // deduct the elapsed time since previous write() completed
+ if (nowTsValid && mWriteTsValid) {
+ time_t sec = nowTs.tv_sec - mWriteTs.tv_sec;
+ long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec;
+ if (nsec < 0) {
+ --sec;
+ nsec += 1000000000;
+ }
+ if (sec == 0) {
+ if ((long) ns > nsec) {
+ ns -= nsec;
+ } else {
+ ns = 0;
+ }
+ }
+ }
+ if (ns > 0) {
+ const struct timespec req = {0, ns};
+ nanosleep(&req, NULL);
+ }
+ // record the time that this write() completed
+ if (nowTsValid) {
+ mWriteTs = nowTs;
+ if ((mWriteTs.tv_nsec += ns) >= 1000000000) {
+ mWriteTs.tv_nsec -= 1000000000;
+ ++mWriteTs.tv_sec;
+ }
+ }
+ mWriteTsValid = nowTsValid;
}
mFramesWritten += totalFramesWritten;
return totalFramesWritten;
}
+void MonoPipe::setAvgFrames(size_t setpoint)
+{
+ mSetpoint = setpoint;
+}
+
} // namespace android
diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h
index aaaa51f..f6e2cb3 100644
--- a/services/audioflinger/MonoPipe.h
+++ b/services/audioflinger/MonoPipe.h
@@ -58,7 +58,9 @@ public:
// average number of frames present in the pipe under normal conditions.
// See throttling mechanism in MonoPipe::write()
- size_t getAvgFrames() const { return (mReqFrames * 11) / 16; }
+ size_t getAvgFrames() const { return mSetpoint; }
+ void setAvgFrames(size_t setpoint);
+ size_t maxFrames() const { return mMaxFrames; }
private:
const size_t mReqFrames; // as requested in constructor, unrounded
@@ -71,6 +73,9 @@ private:
// read by writer with android_atomic_acquire_load
volatile int32_t mRear; // written by writer with android_atomic_release_store,
// read by reader with android_atomic_acquire_load
+ bool mWriteTsValid; // whether mWriteTs is valid
+ struct timespec mWriteTs; // time that the previous write() completed
+ size_t mSetpoint; // target value for pipe fill depth
const bool mWriteCanBlock; // whether write() should block if the pipe is full
};