summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
};