Implement client playback timestamps with 64 bit accuracy

Provide server timestamps if the HAL doesn't provide it.
Provide monotonic - boottime translation.

Bug: 17472992
Bug: 26682703
Bug: 27749434
Change-Id: I6c9b213d9f9284092e34d57f52870e02c72df62a
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e70c611..1de91bf 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -500,6 +500,8 @@
     mTimestampStartupGlitchReported = false;
     mRetrogradeMotionReported = false;
     mUnderrunCountOffset = 0;
+    mFramesWritten = 0;
+    mFramesWrittenServerOffset = 0;
 
     return NO_ERROR;
 }
@@ -537,6 +539,14 @@
         // Note: the if is technically unnecessary because previousState == STATE_FLUSHED
         // is only for streaming tracks, and mMarkerReached is already set to false.
         if (previousState == STATE_STOPPED) {
+            // read last server side position change via timestamp
+            ExtendedTimestamp ets;
+            if (mProxy->getTimestamp(&ets) == OK &&
+                    ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
+                mFramesWrittenServerOffset = -(ets.mPosition[ExtendedTimestamp::LOCATION_SERVER]
+                                                             + ets.mFlushed);
+            }
+            mFramesWritten = 0;
             mProxy->clearTimestamp(); // need new server push for valid timestamp
             mMarkerReached = false;
         }
@@ -1657,6 +1667,9 @@
         releaseBuffer(&audioBuffer);
     }
 
+    if (written > 0) {
+        mFramesWritten += written / mFrameSize;
+    }
     return written;
 }
 
@@ -1923,6 +1936,7 @@
         requested = &timeout;
     }
 
+    size_t writtenFrames = 0;
     while (mRemainingFrames > 0) {
 
         Buffer audioBuffer;
@@ -2024,6 +2038,7 @@
         }
 
         releaseBuffer(&audioBuffer);
+        writtenFrames += releasedFrames;
 
         // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
         // if callback doesn't like to accept the full chunk
@@ -2047,6 +2062,10 @@
 #endif
 
     }
+    if (writtenFrames > 0) {
+        AutoMutex lock(mLock);
+        mFramesWritten += writtenFrames;
+    }
     mRemainingFrames = notificationFrames;
     mRetryOnPartialBuffer = true;
 
@@ -2109,6 +2128,7 @@
         }
         if (mState == STATE_ACTIVE) {
             result = mAudioTrack->start();
+            mFramesWrittenServerOffset = mFramesWritten; // server resets to zero so we offset
         }
     }
     if (result != NO_ERROR) {
@@ -2162,6 +2182,42 @@
     return mAudioTrack->setParameters(keyValuePairs);
 }
 
+status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
+{
+    if (timestamp == nullptr) {
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    if (mCblk->mFlags & CBLK_INVALID) {
+        const status_t status = restoreTrack_l("getTimestampExtended");
+        if (status != OK) {
+            // per getTimestamp() API doc in header, we return DEAD_OBJECT here,
+            // recommending that the track be recreated.
+            return DEAD_OBJECT;
+        }
+    }
+    // check for offloaded/direct here in case restoring somehow changed those flags.
+    if (isOffloadedOrDirect_l()) {
+        return INVALID_OPERATION; // not supported
+    }
+    status_t status = mProxy->getTimestamp(timestamp);
+    bool found = false;
+    if (status == OK) {
+        timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesWritten;
+        timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+        // server side frame offset in case AudioTrack has been restored.
+        for (int i = ExtendedTimestamp::LOCATION_SERVER;
+                i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+            if (timestamp->mTimeNs[i] >= 0) {
+                // apply server offset and the "flush frame correction here"
+                timestamp->mPosition[i] += mFramesWrittenServerOffset + timestamp->mFlushed;
+                found = true;
+            }
+        }
+    }
+    return found ? OK : WOULD_BLOCK;
+}
+
 status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
 {
     AutoMutex lock(mLock);