nuplayer: wait for sync point at renderer flush

Bug: 136232244
Test: atest CtsMediaTestCases:MediaRandomTest#testPlayerRandomActionH264 (100 times)
Change-Id: I0a63df739fb15597130f50a12d6cddbe3ae815e8
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 39be40d..c30f048 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -33,6 +33,7 @@
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/VideoFrameScheduler.h>
 #include <media/MediaCodecBuffer.h>
+#include <utils/SystemClock.h>
 
 #include <inttypes.h>
 
@@ -156,6 +157,7 @@
     CHECK(mediaClock != NULL);
     mPlaybackRate = mPlaybackSettings.mSpeed;
     mMediaClock->setPlaybackRate(mPlaybackRate);
+    (void)mSyncFlag.test_and_set();
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -326,9 +328,27 @@
         mSyncQueues = false;
     }
 
+    // Wait until the current job in the message queue is done, to make sure
+    // buffer processing from the old generation is finished. After the current
+    // job is finished, access to buffers are protected by generation.
+    Mutex::Autolock syncLock(mSyncLock);
+    int64_t syncCount = mSyncCount;
+    mSyncFlag.clear();
+
+    // Make sure message queue is not empty after mSyncFlag is cleared.
     sp<AMessage> msg = new AMessage(kWhatFlush, this);
     msg->setInt32("audio", static_cast<int32_t>(audio));
     msg->post();
+
+    int64_t uptimeMs = uptimeMillis();
+    while (mSyncCount == syncCount) {
+        (void)mSyncCondition.waitRelative(mSyncLock, ms2ns(1000));
+        if (uptimeMillis() - uptimeMs > 1000) {
+            ALOGW("flush(): no wake-up from sync point for 1s; stop waiting to "
+                  "prevent being stuck indefinitely.");
+            break;
+        }
+    }
 }
 
 void NuPlayer::Renderer::signalTimeDiscontinuity() {
@@ -781,6 +801,11 @@
             TRESPASS();
             break;
     }
+    if (!mSyncFlag.test_and_set()) {
+        Mutex::Autolock syncLock(mSyncLock);
+        ++mSyncCount;
+        mSyncCondition.broadcast();
+    }
 }
 
 void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {