diff options
author | Glenn Kasten <gkasten@google.com> | 2012-06-07 10:17:54 -0700 |
---|---|---|
committer | Glenn Kasten <gkasten@google.com> | 2012-06-08 10:09:22 -0700 |
commit | 28ed2f93324988767b5658eba7c1fa781a275183 (patch) | |
tree | 07ba39f61d41aa6ff2af76dc2c9122a102c92059 | |
parent | a4f7e0e9a0e92a063f1b3a08988cf46e2cf1fa94 (diff) | |
download | frameworks_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.h | 2 | ||||
-rw-r--r-- | media/libmedia/AudioParameter.cpp | 1 | ||||
-rw-r--r-- | services/audioflinger/Android.mk | 3 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 23 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 1 | ||||
-rw-r--r-- | services/audioflinger/MonoPipe.cpp | 71 | ||||
-rw-r--r-- | services/audioflinger/MonoPipe.h | 7 |
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 }; |