Warmup cycles must be in range and consecutive

Change-Id: Ie8a40ec3547bdd62a1e2e05b11fb107c25841784
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 1c4f670..255496e 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -138,13 +138,15 @@
             underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
             overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
             forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
-            warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
+            warmupNsMin = (frameCount * 750000000LL) / sampleRate;  // 0.75
+            warmupNsMax = (frameCount * 1250000000LL) / sampleRate; // 1.25
         } else {
             periodNs = 0;
             underrunNs = 0;
             overrunNs = 0;
             forceNs = 0;
-            warmupNs = 0;
+            warmupNsMin = 0;
+            warmupNsMax = LONG_MAX;
         }
         readBufferState = -1;
         dumpState->mFrameCount = frameCount;
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 67e2e6e..8b12f28 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -195,13 +195,15 @@
             underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
             overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
             forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
-            warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
+            warmupNsMin = (frameCount * 750000000LL) / sampleRate;  // 0.75
+            warmupNsMax = (frameCount * 1250000000LL) / sampleRate; // 1.25
         } else {
             periodNs = 0;
             underrunNs = 0;
             overrunNs = 0;
             forceNs = 0;
-            warmupNs = 0;
+            warmupNsMin = 0;
+            warmupNsMax = LONG_MAX;
         }
         mMixerBufferState = UNDEFINED;
 #if !LOG_NDEBUG
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 3e12cca..b69cc85 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -29,7 +29,8 @@
 
 #define FAST_DEFAULT_NS    999999999L   // ~1 sec: default time to sleep
 #define FAST_HOT_IDLE_NS     1000000L   // 1 ms: time to sleep while hot idling
-#define MIN_WARMUP_CYCLES          2    // minimum number of loop cycles to wait for warmup
+#define MIN_WARMUP_CYCLES          2    // minimum number of consecutive in-range loop cycles
+                                        // to wait for warmup
 #define MAX_WARMUP_CYCLES         10    // maximum number of loop cycles to wait for warmup
 
 namespace android {
@@ -44,7 +45,8 @@
     underrunNs(0),
     overrunNs(0),
     forceNs(0),
-    warmupNs(0),
+    warmupNsMin(0),
+    warmupNsMax(LONG_MAX),
     // re-initialized to &dummyDumpState by subclass constructor
     mDummyDumpState(NULL),
     dumpState(NULL),
@@ -60,6 +62,7 @@
     isWarm(false),
     /* measuredWarmupTs({0, 0}), */
     warmupCycles(0),
+    warmupConsecutiveInRangeCycles(0),
     // dummyLogWriter
     logWriter(&dummyLogWriter),
     timestampStatus(INVALID_OPERATION),
@@ -169,6 +172,7 @@
                 measuredWarmupTs.tv_sec = 0;
                 measuredWarmupTs.tv_nsec = 0;
                 warmupCycles = 0;
+                warmupConsecutiveInRangeCycles = 0;
                 sleepNs = -1;
                 coldGen = current->mColdGen;
 #ifdef FAST_MIXER_STATISTICS
@@ -222,7 +226,8 @@
                 // To avoid an initial underrun on fast tracks after exiting standby,
                 // do not start pulling data from tracks and mixing until warmup is complete.
                 // Warmup is considered complete after the earlier of:
-                //      MIN_WARMUP_CYCLES write() attempts and last one blocks for at least warmupNs
+                //      MIN_WARMUP_CYCLES consecutive in-range write() attempts,
+                //          where "in-range" means warmupNsMin <= cycle time <= warmupNsMax
                 //      MAX_WARMUP_CYCLES write() attempts.
                 // This is overly conservative, but to get better accuracy requires a new HAL API.
                 if (!isWarm && attemptedWrite) {
@@ -233,7 +238,14 @@
                         measuredWarmupTs.tv_nsec -= 1000000000;
                     }
                     ++warmupCycles;
-                    if ((nsec > warmupNs && warmupCycles >= MIN_WARMUP_CYCLES) ||
+                    if (warmupNsMin <= nsec && nsec <= warmupNsMax) {
+                        ALOGV("warmup cycle %d in range: %.03f ms", warmupCycles, nsec * 1e-9);
+                        ++warmupConsecutiveInRangeCycles;
+                    } else {
+                        ALOGV("warmup cycle %d out of range: %.03f ms", warmupCycles, nsec * 1e-9);
+                        warmupConsecutiveInRangeCycles = 0;
+                    }
+                    if ((warmupConsecutiveInRangeCycles >= MIN_WARMUP_CYCLES) ||
                             (warmupCycles >= MAX_WARMUP_CYCLES)) {
                         isWarm = true;
                         dumpState->mMeasuredWarmupTs = measuredWarmupTs;
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 1330334..cb32e9d 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -58,7 +58,8 @@
     long underrunNs;    // underrun likely when write cycle is greater than this value
     long overrunNs;     // overrun likely when write cycle is less than this value
     long forceNs;       // if overrun detected, force the write cycle to take this much time
-    long warmupNs;      // warmup complete when write cycle is greater than to this value
+    long warmupNsMin;   // warmup complete when write cycle is greater than or equal to this value
+    long warmupNsMax;   //                                 and less than or equal to this value
     FastThreadDumpState *mDummyDumpState;
     FastThreadDumpState *dumpState;
     bool ignoreNextOverrun;  // used to ignore initial overrun and first after an underrun
@@ -74,7 +75,8 @@
     unsigned coldGen;   // last observed mColdGen
     bool isWarm;        // true means ready to mix, false means wait for warmup before mixing
     struct timespec measuredWarmupTs;  // how long did it take for warmup to complete
-    uint32_t warmupCycles;  // counter of number of loop cycles required to warmup
+    uint32_t warmupCycles;  // counter of number of loop cycles during warmup phase
+    uint32_t warmupConsecutiveInRangeCycles;    // number of consecutive cycles in range
     NBLog::Writer dummyLogWriter;
     NBLog::Writer *logWriter;
     status_t timestampStatus;