Add AudioRecord timestamps

Bug: 13569372
Bug: 22886739
Change-Id: Ibc81afefb733d23676a632a0f2da31163fdbe05f
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1c0d904..ec57d96 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -284,6 +284,8 @@
     mSequence = 1;
     mObservedSequence = mSequence;
     mInOverrun = false;
+    mFramesRead = 0;
+    mFramesReadServerOffset = 0;
 
     return NO_ERROR;
 }
@@ -299,6 +301,12 @@
         return NO_ERROR;
     }
 
+    // discard data in buffer
+    const uint32_t framesFlushed = mProxy->flush();
+    mFramesReadServerOffset -= mFramesRead + framesFlushed;
+    mFramesRead = 0;
+    mProxy->clearTimestamp();  // timestamp is invalid until next server push
+
     // reset current position as seen by client to 0
     mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
     // force refresh of remaining frames by processAudioBuffer() as last
@@ -449,6 +457,27 @@
     return AudioSystem::getInputFramesLost(getInputPrivate());
 }
 
+status_t AudioRecord::getTimestamp(ExtendedTimestamp *timestamp)
+{
+    if (timestamp == nullptr) {
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    status_t status = mProxy->getTimestamp(timestamp);
+    if (status == OK) {
+        timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
+        timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+        // server side frame offset in case AudioRecord has been restored.
+        for (int i = ExtendedTimestamp::LOCATION_SERVER;
+                i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+            if (timestamp->mTimeNs[i] >= 0) {
+                timestamp->mPosition[i] += mFramesReadServerOffset;
+            }
+        }
+    }
+    return status;
+}
+
 // ---- Explicit Routing ---------------------------------------------------
 status_t AudioRecord::setInputDevice(audio_port_handle_t deviceId) {
     AutoMutex lock(mLock);
@@ -837,7 +866,10 @@
 
         releaseBuffer(&audioBuffer);
     }
-
+    if (read > 0) {
+        mFramesRead += read / mFrameSize;
+        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+    }
     return read;
 }
 
@@ -988,6 +1020,7 @@
         requested = &timeout;
     }
 
+    size_t readFrames = 0;
     while (mRemainingFrames > 0) {
 
         Buffer audioBuffer;
@@ -1049,6 +1082,7 @@
         }
 
         releaseBuffer(&audioBuffer);
+        readFrames += 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
@@ -1072,6 +1106,11 @@
 #endif
 
     }
+    if (readFrames > 0) {
+        AutoMutex lock(mLock);
+        mFramesRead += readFrames;
+        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+    }
     mRemainingFrames = notificationFrames;
     mRetryOnPartialBuffer = true;
 
@@ -1096,6 +1135,7 @@
             // FIXME this fails if we have a new AudioFlinger instance
             result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
         }
+        mFramesReadServerOffset = mFramesRead; // server resets to zero so we need an offset.
     }
     if (result != NO_ERROR) {
         ALOGW("restoreRecord_l() failed status %d", result);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index d75ad87..988386e 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -597,7 +597,7 @@
 ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
         size_t frameSize, bool isOut, bool clientInServer)
     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
-      mAvailToClient(0), mFlush(0)
+      mAvailToClient(0), mFlush(0), mReleased(0)
 {
 }
 
@@ -733,6 +733,7 @@
     }
 
     cblk->mServer += stepCount;
+    mReleased += stepCount;
 
     size_t half = mFrameCount / 2;
     if (half == 0) {
@@ -1033,6 +1034,8 @@
     mFramesReadySafe = clampToSize(mFramesReady);
 
     cblk->mServer += stepCount;
+    mReleased += stepCount;
+
     // This may overflow, but client is not supposed to rely on it
     StaticAudioTrackPosLoop posLoop;
     posLoop.mBufferPosition = mState.mPosition;