Properly implement asynchronous preparation of media playback.

related-to-bug: 2413002
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index f42d55b..1bfcf65 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -49,30 +49,11 @@
 }
 
 status_t StagefrightPlayer::prepare() {
-    LOGV("prepare");
-
-    int32_t width, height;
-    if (mPlayer->getVideoDimensions(&width, &height) != OK) {
-        width = height = 0;
-    }
-
-    sendEvent(MEDIA_SET_VIDEO_SIZE, width, height);
-
-    return OK;
+    return mPlayer->prepare();
 }
 
 status_t StagefrightPlayer::prepareAsync() {
-    LOGV("prepareAsync");
-
-    status_t err = prepare();
-
-    if (err != OK) {
-        return err;
-    }
-
-    sendEvent(MEDIA_PREPARED);
-
-    return OK;
+    return mPlayer->prepareAsync();
 }
 
 status_t StagefrightPlayer::start() {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 2b403f8..d25f7f6 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -37,21 +37,23 @@
 namespace android {
 
 struct AwesomeEvent : public TimedEventQueue::Event {
-    AwesomeEvent(AwesomePlayer *player, int32_t code)
+    AwesomeEvent(
+            AwesomePlayer *player,
+            void (AwesomePlayer::*method)())
         : mPlayer(player),
-          mCode(code) {
+          mMethod(method) {
     }
 
 protected:
     virtual ~AwesomeEvent() {}
 
     virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
-        mPlayer->onEvent(mCode);
+        (mPlayer->*mMethod)();
     }
 
 private:
     AwesomePlayer *mPlayer;
-    int32_t mCode;
+    void (AwesomePlayer::*mMethod)();
 
     AwesomeEvent(const AwesomeEvent &);
     AwesomeEvent &operator=(const AwesomeEvent &);
@@ -115,13 +117,16 @@
 
     DataSource::RegisterDefaultSniffers();
 
-    mVideoEvent = new AwesomeEvent(this, 0);
+    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
     mVideoEventPending = false;
-    mStreamDoneEvent = new AwesomeEvent(this, 1);
+    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
     mStreamDoneEventPending = false;
-    mBufferingEvent = new AwesomeEvent(this, 2);
+    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
     mBufferingEventPending = false;
-    mCheckAudioStatusEvent = new AwesomeEvent(this, 3);
+
+    mCheckAudioStatusEvent = new AwesomeEvent(
+            this, &AwesomePlayer::onCheckAudioStatus);
+
     mAudioStatusEventPending = false;
 
     mQueue.start();
@@ -287,12 +292,12 @@
     mPrefetcher.clear();
 }
 
-void AwesomePlayer::notifyListener_l(int msg, int ext1) {
+void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
     if (mListener != NULL) {
         sp<MediaPlayerBase> listener = mListener.promote();
 
         if (listener != NULL) {
-            listener->sendEvent(msg, ext1);
+            listener->sendEvent(msg, ext1, ext2);
         }
     }
 }
@@ -623,18 +628,7 @@
     return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
 }
 
-void AwesomePlayer::onEvent(int32_t code) {
-    if (code == 1) {
-        onStreamDone();
-        return;
-    } else if (code == 2) {
-        onBufferingUpdate();
-        return;
-    } else if (code == 3) {
-        onCheckAudioStatus();
-        return;
-    }
-
+void AwesomePlayer::onVideoEvent() {
     Mutex::Autolock autoLock(mLock);
 
     mVideoEventPending = false;
@@ -819,5 +813,65 @@
     postCheckAudioStatusEvent_l();
 }
 
+status_t AwesomePlayer::prepare() {
+    Mutex::Autolock autoLock(mLock);
+
+    status_t err = prepareAsync_l();
+
+    if (err != OK) {
+        return err;
+    }
+
+    while (mAsyncPrepareEvent != NULL) {
+        mPreparedCondition.wait(mLock);
+    }
+
+    return OK;
+}
+
+status_t AwesomePlayer::prepareAsync() {
+    Mutex::Autolock autoLock(mLock);
+    return prepareAsync_l();
+}
+
+status_t AwesomePlayer::prepareAsync_l() {
+    if (mAsyncPrepareEvent != NULL) {
+        return UNKNOWN_ERROR;  // async prepare already pending.
+    }
+
+    mAsyncPrepareEvent = new AwesomeEvent(
+            this, &AwesomePlayer::onPrepareAsyncEvent);
+
+    mQueue.postEvent(mAsyncPrepareEvent);
+
+    return OK;
+}
+
+void AwesomePlayer::onPrepareAsyncEvent() {
+    sp<Prefetcher> prefetcher;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+        prefetcher = mPrefetcher;
+    }
+
+    if (prefetcher != NULL) {
+        prefetcher->prepare();
+    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mVideoWidth < 0 || mVideoHeight < 0) {
+        notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
+    } else {
+        notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+    }
+
+    notifyListener_l(MEDIA_PREPARED);
+
+    mAsyncPrepareEvent = NULL;
+    mPreparedCondition.signal();
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 862998a..835e167 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -171,7 +171,7 @@
     }
 }
 
-int64_t Prefetcher::getCachedDurationUs() {
+int64_t Prefetcher::getCachedDurationUs(bool *noMoreData) {
     Mutex::Autolock autoLock(mLock);
 
     int64_t minCacheDurationUs = -1;
@@ -197,9 +197,25 @@
         }
     }
 
+    if (noMoreData) {
+        *noMoreData = minCacheDurationUs < 0;
+    }
+
     return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
 }
 
+status_t Prefetcher::prepare() {
+    // Buffer about 2 secs worth of data on prepare.
+
+    int64_t duration;
+    bool noMoreData;
+    do {
+        duration = getCachedDurationUs(&noMoreData);
+    } while (!noMoreData && duration < 2000000);
+
+    return OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 PrefetchedSource::PrefetchedSource(
@@ -232,15 +248,6 @@
 
     mStarted = true;
 
-    for (;;) {
-        // Buffer 2 secs on startup.
-        if (mReachedEOS || mCacheDurationUs > 2000000) {
-            break;
-        }
-
-        mCondition.wait(mLock);
-    }
-
     return OK;
 }
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 75e71e6..651b910 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -57,6 +57,10 @@
 
     void reset();
 
+    status_t prepare();
+    status_t prepareAsync();
+    status_t prepareAsync_l();
+
     status_t play();
     status_t pause();
 
@@ -121,6 +125,9 @@
     sp<TimedEventQueue::Event> mCheckAudioStatusEvent;
     bool mAudioStatusEventPending;
 
+    sp<TimedEventQueue::Event> mAsyncPrepareEvent;
+    Condition mPreparedCondition;
+
     void postVideoEvent_l(int64_t delayUs = -1);
     void postBufferingEvent_l();
     void postStreamDoneEvent_l();
@@ -143,13 +150,14 @@
     status_t setAudioSource(sp<MediaSource> source);
     status_t setVideoSource(sp<MediaSource> source);
 
-    void onEvent(int32_t code);
     void onStreamDone();
 
-    void notifyListener_l(int msg, int ext1 = 0);
+    void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
 
+    void onVideoEvent();
     void onBufferingUpdate();
     void onCheckAudioStatus();
+    void onPrepareAsyncEvent();
 
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h
index 7a97785..d227864 100644
--- a/media/libstagefright/include/Prefetcher.h
+++ b/media/libstagefright/include/Prefetcher.h
@@ -34,7 +34,9 @@
     // that will benefit from prefetching/caching the original one.
     sp<MediaSource> addSource(const sp<MediaSource> &source);
 
-    int64_t getCachedDurationUs();
+    int64_t getCachedDurationUs(bool *noMoreData = NULL);
+
+    status_t prepare();
 
 protected:
     virtual ~Prefetcher();