diff options
-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 }; |