am ea5008d8: am 28ed2f93: Reduce underruns in screen off, esp. with EQ

* commit 'ea5008d8abfdf1479b4efa266cdb7c842d168aa9':
  Reduce underruns in screen off, esp. with EQ
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 @@
     //  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::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_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 d944d32..c5ae2ee 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -164,6 +164,9 @@
     //  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 @@
                 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 @@
         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 @@
         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 @@
 #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 @@
         // 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 @@
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
         mFront(0),
         mRear(0),
+        mWriteTsValid(false),
+        // mWriteTs
+        mSetpoint((reqFrames * 11) / 16),
         mWriteCanBlock(writeCanBlock)
 {
 }
@@ -87,40 +91,75 @@
         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 @@
 
             // 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 @@
                                     // 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
 };