Implement Track::getTimestamp()

using a new timestamp latch in PlaybackThread, and
AudioTrackServerProxy::framesReleased() which returns mServer.

Change-Id: I1ebfba968c773faaab95648c272fd3ebd74718d6
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2c2931f..bc01ede 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -943,7 +943,9 @@
         mDraining(false),
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
-        mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1)
+        mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
+        // mLatchD, mLatchQ,
+        mLatchDValid(false), mLatchQValid(false)
 {
     snprintf(mName, kNameLength, "AudioOut_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
@@ -1818,6 +1820,14 @@
         } else {
             bytesWritten = framesWritten;
         }
+        status_t status = INVALID_OPERATION;    // mLatchD.mTimestamp is invalid
+        if (status == NO_ERROR) {
+            size_t totalFramesWritten = mNormalSink->framesWritten();
+            if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
+                mLatchD.mUnpresentedFrames = totalFramesWritten - mLatchD.mTimestamp.mPosition;
+                mLatchDValid = true;
+            }
+        }
     // otherwise use the HAL / AudioStreamOut directly
     } else {
         // Direct output and offload threads
@@ -2096,6 +2106,12 @@
                 logString = NULL;
             }
 
+            if (mLatchDValid) {
+                mLatchQ = mLatchD;
+                mLatchDValid = false;
+                mLatchQValid = true;
+            }
+
             if (checkForNewParameters_l()) {
                 cacheParameters_l();
             }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 31d5323..1333de2 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -606,6 +606,17 @@
                 // accessed by both binder threads and within threadLoop(), lock on mutex needed
                 unsigned    mFastTrackAvailMask;    // bit i set if fast track [i] is available
     virtual     void        flushOutput_l();
+
+private:
+    // timestamp latch:
+    //  D input is written by threadLoop_write while mutex is unlocked, and read while locked
+    //  Q output is written while locked, and read while locked
+    struct {
+        AudioTimestamp  mTimestamp;
+        uint32_t        mUnpresentedFrames;
+    } mLatchD, mLatchQ;
+    bool mLatchDValid;  // true means mLatchD is valid, and clock it into latch at next opportunity
+    bool mLatchQValid;  // true means mLatchQ is valid
 };
 
 class MixerThread : public PlaybackThread {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 687217b..9622709 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -724,7 +724,19 @@
     }
     Mutex::Autolock _l(thread->mLock);
     PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
-    return INVALID_OPERATION;
+    if (!playbackThread->mLatchQValid) {
+        return INVALID_OPERATION;
+    }
+    uint32_t unpresentedFrames =
+            ((int64_t) playbackThread->mLatchQ.mUnpresentedFrames * mSampleRate) /
+            playbackThread->mSampleRate;
+    uint32_t framesWritten = mAudioTrackServerProxy->framesReleased();
+    if (framesWritten < unpresentedFrames) {
+        return INVALID_OPERATION;
+    }
+    timestamp.mPosition = framesWritten - unpresentedFrames;
+    timestamp.mTime = playbackThread->mLatchQ.mTimestamp.mTime;
+    return NO_ERROR;
 }
 
 status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)