Improve timestamp jitter fix

Use last valid kernel timestamp on server side, not client side.

Bug: 28465713
Change-Id: I33590d6922980f288355f947bc56279245058429
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index 4f504a4..44d6c0b 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -37,9 +37,16 @@
 struct ExtendedTimestamp {
     enum Location {
         LOCATION_INVALID = -1,
-        LOCATION_CLIENT,   // timestamp of last read frame from client-server track buffer
-        LOCATION_SERVER,   // timestamp of newest frame from client-server track buffer
+        // Locations in the audio playback / record pipeline.
+        LOCATION_CLIENT,   // timestamp of last read frame from client-server track buffer.
+        LOCATION_SERVER,   // timestamp of newest frame from client-server track buffer.
         LOCATION_KERNEL,   // timestamp of newest frame in the kernel (alsa) buffer.
+
+        // Historical data: info when the kernel timestamp was OK (prior to the newest frame).
+        // This may be useful when the newest frame kernel timestamp is unavailable.
+        // Available for playback timestamps.
+        LOCATION_SERVER_LASTKERNELOK, // timestamp of server the prior time kernel timestamp OK.
+        LOCATION_KERNEL_LASTKERNELOK, // timestamp of kernel the prior time kernel timestamp OK.
         LOCATION_MAX       // for sizing arrays only
     };
 
@@ -101,7 +108,7 @@
         // look for the closest-to-hw stage in the pipeline with a valid timestamp.
         // We omit LOCATION_CLIENT as we prefer at least LOCATION_SERVER based accuracy
         // when getting the best timestamp.
-        for (int i = LOCATION_MAX - 1; i >= LOCATION_SERVER; --i) {
+        for (int i = LOCATION_KERNEL; i >= LOCATION_SERVER; --i) {
             if (mTimeNs[i] > 0) {
                 *position = mPosition[i];
                 *time = mTimeNs[i] + mTimebaseOffset[timebase];
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 46948e4..88c4e61 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -1047,7 +1047,6 @@
     bool                    mRetrogradeMotionReported; // reduce log spam
     AudioTimestamp          mPreviousTimestamp;     // used to detect retrograde motion
     ExtendedTimestamp::Location mPreviousLocation;  // location used for previous timestamp
-    double                  mComputedLatencyMs;     // latency between server and kernel
 
     uint32_t                mUnderrunCountOffset;   // updated when restoring tracks
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index babe4ed..22a5acd 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -536,7 +536,6 @@
     mTimestampStartupGlitchReported = false;
     mRetrogradeMotionReported = false;
     mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
-    mComputedLatencyMs = 0.;
     mUnderrunCountOffset = 0;
     mFramesWritten = 0;
     mFramesWrittenServerOffset = 0;
@@ -570,7 +569,6 @@
         mTimestampStartupGlitchReported = false;
         mRetrogradeMotionReported = false;
         mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
-        mComputedLatencyMs = 0.;
 
         // read last server side position change via timestamp.
         ExtendedTimestamp ets;
@@ -2375,25 +2373,22 @@
                 if (location == ExtendedTimestamp::LOCATION_SERVER) {
                     ALOGW_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_KERNEL,
                             "getTimestamp() location moved from kernel to server");
-                    const double latencyMs = mComputedLatencyMs > 0.
-                            ? mComputedLatencyMs : mAfLatency;
                     const int64_t frames =
-                            int64_t(latencyMs * mSampleRate * mPlaybackRate.mSpeed / 1000);
-                    ALOGV("mComputedLatencyMs:%lf  mAfLatency:%u  frame adjustment:%lld",
-                            mComputedLatencyMs, mAfLatency, (long long)frames);
+                            (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
+                            ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0)
+                            ?
+                            int64_t((double)mAfLatency * mSampleRate * mPlaybackRate.mSpeed
+                                    / 1000)
+                            :
+                            (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
+                            - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK]);
+                    ALOGV("frame adjustment:%lld  timestamp:%s",
+                            (long long)frames, ets.toString().c_str());
                     if (frames >= ets.mPosition[location]) {
                         timestamp.mPosition = 0;
                     } else {
                         timestamp.mPosition = (uint32_t)(ets.mPosition[location] - frames);
                     }
-                } else if (location == ExtendedTimestamp::LOCATION_KERNEL) {
-                    const double bufferDiffMs =
-                            (double)(ets.mPosition[ExtendedTimestamp::LOCATION_SERVER]
-                                   - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL])
-                                   * 1000 / ((double)mSampleRate * mPlaybackRate.mSpeed);
-                    mComputedLatencyMs = bufferDiffMs > 0. ? bufferDiffMs : 0.;
-                    ALOGV("mComputedLatencyMs:%lf  mAfLatency:%d",
-                            mComputedLatencyMs, mAfLatency);
                 }
                 mPreviousLocation = location;
             } else {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 228426a..bee0447 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2899,6 +2899,24 @@
                 // sink will block whie writing.
                 ExtendedTimestamp timestamp; // use private copy to fetch
                 (void) mNormalSink->getTimestamp(timestamp);
+
+                // We keep track of the last valid kernel position in case we are in underrun
+                // and the normal mixer period is the same as the fast mixer period, or there
+                // is some error from the HAL.
+                if (mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] >= 0) {
+                    mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] =
+                            mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
+                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] =
+                            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+
+                    mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] =
+                            mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER];
+                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] =
+                            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER];
+                } else {
+                    ALOGV("getTimestamp error - no valid kernel position");
+                }
+
                 // copy over kernel info
                 mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
                         timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9d430aa..41cb030 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1103,7 +1103,7 @@
         if (local.mTimeNs[i] > 0) {
             local.mPosition[i] = mFrameMap.findX(local.mPosition[i]);
             // check drain state from the latest stage in the pipeline.
-            if (!checked) {
+            if (!checked && i <= ExtendedTimestamp::LOCATION_KERNEL) {
                 mAudioTrackServerProxy->setDrained(
                         local.mPosition[i] >= mAudioTrackServerProxy->framesReleased());
                 checked = true;