Enable FastTrack timestamps

Bug: 26413951
Change-Id: I99a69241a0bcd69f6bfebf785cac6d9ee1e2cd5f
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 2270c85..cae5560 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -119,8 +119,11 @@
 
 typedef SingleStateQueue<AudioPlaybackRate> PlaybackRateQueue;
 
+
 typedef SingleStateQueue<ExtendedTimestamp> ExtendedTimestampQueue;
 
+typedef SingleStateQueue<AudioTimestamp> TimestampQueue;
+
 // ----------------------------------------------------------------------------
 
 // Important: do not add any virtual methods, including ~
@@ -175,7 +178,9 @@
                 uint16_t    mPad2;           // unused
 
                 // server write-only, client read
-                ExtendedTimestampQueue::Shared mExtendedTimestampQueue;
+                ExtendedTimestampQueue::Shared mExtendedTimestampQueue; // capture
+                TimestampQueue::Shared mTimestampQueue; // playback
+
 public:
 
     volatile    int32_t     mFlags;         // combinations of CBLK_*
@@ -333,7 +338,10 @@
             size_t frameSize, bool clientInServer = false)
         : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
           clientInServer),
-          mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { }
+          mPlaybackRateMutator(&cblk->mPlaybackRateQueue),
+          mTimestampObserver(&cblk->mTimestampQueue) {
+    }
+
     virtual ~AudioTrackClientProxy() { }
 
     // No barriers on the following operations, so the ordering of loads/stores
@@ -357,6 +365,20 @@
         mPlaybackRateMutator.push(playbackRate);
     }
 
+    status_t    getTimestamp(AudioTimestamp *timestamp) {
+        if (timestamp == nullptr) {
+            return BAD_VALUE;
+        }
+        (void) mTimestampObserver.poll(mTimestamp);
+        // if no data is pushed by server, mTimestamp should be initialized by its constructor
+        // to all zero elements.
+        if (mTimestamp.mTime.tv_sec == 0 && mTimestamp.mTime.tv_nsec == 0) {
+            return WOULD_BLOCK;
+        }
+        *timestamp = mTimestamp;
+        return OK;
+    }
+
     virtual void flush();
 
     virtual uint32_t    getUnderrunFrames() const {
@@ -374,6 +396,8 @@
 
 private:
     PlaybackRateQueue::Mutator   mPlaybackRateMutator;
+    TimestampQueue::Observer mTimestampObserver;
+    AudioTimestamp mTimestamp;
 };
 
 class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
@@ -522,7 +546,8 @@
             size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
         : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
           mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
-          mUnderrunCount(0), mUnderrunning(false) {
+          mUnderrunCount(0), mUnderrunning(false),
+          mTimestampMutator(&cblk->mTimestampQueue) {
         mCblk->mSampleRate = sampleRate;
         mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
     }
@@ -562,6 +587,11 @@
     // Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
     AudioPlaybackRate getPlaybackRate();
 
+    // Expose timestamp to client proxy. Should only be called by a single thread.
+                   void setTimestamp(const AudioTimestamp &timestamp) {
+                       mTimestampMutator.push(timestamp);
+                   }
+
 private:
     AudioPlaybackRate             mPlaybackRate;  // last observed playback rate
     PlaybackRateQueue::Observer   mPlaybackRateObserver;
@@ -569,6 +599,8 @@
     // The server keeps a copy here where it is safe from the client.
     uint32_t                      mUnderrunCount; // echoed to mCblk
     bool                          mUnderrunning;  // used to detect edge of underrun
+
+    TimestampQueue::Mutator       mTimestampMutator;
 };
 
 class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e17e47e..132ae38 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2167,11 +2167,6 @@
     // Set false here to cover all the error return cases.
     mPreviousTimestampValid = false;
 
-    // FIXME not implemented for fast tracks; should use proxy and SSQ
-    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-        return INVALID_OPERATION;
-    }
-
     switch (mState) {
     case STATE_ACTIVE:
     case STATE_PAUSED:
@@ -2201,7 +2196,10 @@
 
     // The presented frame count must always lag behind the consumed frame count.
     // To avoid a race, read the presented frames first.  This ensures that presented <= consumed.
-    status_t status = mAudioTrack->getTimestamp(timestamp);
+
+    // FastTrack timestamps are read through shared memory; otherwise use Binder.
+    status_t status = (mFlags & AUDIO_OUTPUT_FLAG_FAST) ?
+            mProxy->getTimestamp(&timestamp) : mAudioTrack->getTimestamp(timestamp);
     if (status != NO_ERROR) {
         ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
         return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1450ca1..9a9e511 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -89,6 +89,7 @@
     // ExtendedAudioBufferProvider interface
     virtual size_t framesReady() const;
     virtual size_t framesReleased() const;
+    virtual void onTimestamp(const AudioTimestamp &timestamp);
 
     bool isPausing() const { return mState == PAUSING; }
     bool isPaused() const { return mState == PAUSED; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b4c1fdd..b5db9fb 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -589,6 +589,11 @@
     return mAudioTrackServerProxy->framesReleased();
 }
 
+void AudioFlinger::PlaybackThread::Track::onTimestamp(const AudioTimestamp &timestamp)
+{
+    mAudioTrackServerProxy->setTimestamp(timestamp);
+}
+
 // Don't call for fast tracks; the framesReady() could result in priority inversion
 bool AudioFlinger::PlaybackThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
@@ -846,7 +851,7 @@
 
 status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
 {
-    // Client should implement this using SSQ; the unpresented frame count in latch is irrelevant
+    // FastTrack timestamps are read through SSQ
     if (isFastTrack()) {
         return INVALID_OPERATION;
     }