NuPlayer: use getTimestamp instead of getPosition

Bug: 14659809
Bug: 16985287
Change-Id: I59ec72fbd40a9b8d28fe548ddad082c03000c045
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 067784b..8ab777a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -343,15 +343,13 @@
                 mFirstAudioTimeUs = mediaTimeUs;
             }
 
-            uint32_t numFramesPlayed;
-            CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
-
-            // TODO: figure out how to calculate initial latency.
-            // Otherwise, the initial time is not correct till the first sample
-            // is played.
-            mAnchorTimeMediaUs = mFirstAudioTimeUs
-                    + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
-            mAnchorTimeRealUs = ALooper::GetNowUs();
+            // TODO: figure out how to calculate initial latency if
+            // getTimestamp is not available. Otherwise, the initial time
+            // is not correct till the first sample is played.
+            int64_t nowUs = ALooper::GetNowUs();
+            mAnchorTimeMediaUs =
+                mFirstAudioTimeUs + getPlayedOutAudioDurationUs(nowUs);
+            mAnchorTimeRealUs = nowUs;
         }
 
         size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -413,7 +411,7 @@
             // EOS
             int64_t postEOSDelayUs = 0;
             if (mAudioSink->needsTrailingPadding()) {
-                postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency();
+                postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
             }
             notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
 
@@ -428,8 +426,8 @@
             ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
             mAnchorTimeMediaUs = mediaTimeUs;
 
-            mAnchorTimeRealUs = ALooper::GetNowUs()
-                    + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2;
+            int64_t nowUs = ALooper::GetNowUs();
+            mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs);
         }
 
         size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -483,12 +481,10 @@
     return !mAudioQueue.empty();
 }
 
-int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() {
-    uint32_t numFramesPlayed;
-    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
-
-    uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed;
-    return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000;
+int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
+    int64_t writtenAudioDurationUs =
+        mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame();
+    return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
 }
 
 void NuPlayer::Renderer::postDrainVideoQueue() {
@@ -937,17 +933,37 @@
     }
 }
 
-void NuPlayer::Renderer::onAudioOffloadTearDown() {
+int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
+    // FIXME: getTimestamp sometimes returns negative frame count.
+    // Since we do not handle the rollover at this point (which can
+    // happen every 14 hours), simply treat the timestamp as signed.
     uint32_t numFramesPlayed;
-    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+    int64_t numFramesPlayedAt;
+    AudioTimestamp ts;
+    status_t res = mAudioSink->getTimestamp(ts);
+    if (res == OK) {
+        numFramesPlayed = ts.mPosition;
+        numFramesPlayedAt =
+            ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+    } else {
+        res = mAudioSink->getPosition(&numFramesPlayed);
+        CHECK_EQ(res, (status_t)OK);
+        numFramesPlayedAt = nowUs;
+        numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
+    }
+    return (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()
+            + nowUs - numFramesPlayedAt;
+}
 
+void NuPlayer::Renderer::onAudioOffloadTearDown() {
     int64_t firstAudioTimeUs;
     {
         Mutex::Autolock autoLock(mLock);
         firstAudioTimeUs = mFirstAudioTimeUs;
     }
-    int64_t currentPositionUs = firstAudioTimeUs
-            + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
+
+    int64_t currentPositionUs =
+        firstAudioTimeUs + getPlayedOutAudioDurationUs(ALooper::GetNowUs());
 
     mAudioSink->stop();
     mAudioSink->flush();