Merge "Support for a "preparation" state that can take care of lengthy"
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 450fae5..b04e7a6 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -106,6 +106,26 @@
 NuPlayer::GenericSource::~GenericSource() {
 }
 
+void NuPlayer::GenericSource::prepareAsync() {
+    if (mVideoTrack.mSource != NULL) {
+        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
+
+        int32_t width, height;
+        CHECK(meta->findInt32(kKeyWidth, &width));
+        CHECK(meta->findInt32(kKeyHeight, &height));
+
+        notifyVideoSizeChanged(width, height);
+    }
+
+    notifyFlagsChanged(
+            FLAG_CAN_PAUSE
+            | FLAG_CAN_SEEK_BACKWARD
+            | FLAG_CAN_SEEK_FORWARD
+            | FLAG_CAN_SEEK);
+
+    notifyPrepared();
+}
+
 void NuPlayer::GenericSource::start() {
     ALOGI("start");
 
@@ -262,8 +282,4 @@
     }
 }
 
-uint32_t NuPlayer::GenericSource::flags() const {
-    return FLAG_SEEKABLE;
-}
-
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index e59ea3a..2da680c 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -42,6 +42,8 @@
             const sp<AMessage> &notify,
             int fd, int64_t offset, int64_t length);
 
+    virtual void prepareAsync();
+
     virtual void start();
 
     virtual status_t feedMoreTSData();
@@ -51,8 +53,6 @@
     virtual status_t getDuration(int64_t *durationUs);
     virtual status_t seekTo(int64_t seekTimeUs);
 
-    virtual uint32_t flags() const;
-
 protected:
     virtual ~GenericSource();
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index d38ee62..ae67906 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -66,7 +66,7 @@
     }
 }
 
-void NuPlayer::HTTPLiveSource::start() {
+void NuPlayer::HTTPLiveSource::prepareAsync() {
     mLiveLooper = new ALooper;
     mLiveLooper->setName("http live");
     mLiveLooper->start();
@@ -81,6 +81,26 @@
             mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
 
     mTSParser = new ATSParser;
+
+    notifyVideoSizeChanged(0, 0);
+
+    uint32_t flags = FLAG_CAN_PAUSE;
+    if (mLiveSession->isSeekable()) {
+        flags |= FLAG_CAN_SEEK;
+        flags |= FLAG_CAN_SEEK_BACKWARD;
+        flags |= FLAG_CAN_SEEK_FORWARD;
+    }
+
+    if (mLiveSession->hasDynamicDuration()) {
+        flags |= FLAG_DYNAMIC_DURATION;
+    }
+
+    notifyFlagsChanged(flags);
+
+    notifyPrepared();
+}
+
+void NuPlayer::HTTPLiveSource::start() {
 }
 
 sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
@@ -194,18 +214,5 @@
     return OK;
 }
 
-uint32_t NuPlayer::HTTPLiveSource::flags() const {
-    uint32_t flags = 0;
-    if (mLiveSession->isSeekable()) {
-        flags |= FLAG_SEEKABLE;
-    }
-
-    if (mLiveSession->hasDynamicDuration()) {
-        flags |= FLAG_DYNAMIC_DURATION;
-    }
-
-    return flags;
-}
-
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 4a217af..269f3c0 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -34,6 +34,7 @@
             bool uidValid = false,
             uid_t uid = 0);
 
+    virtual void prepareAsync();
     virtual void start();
 
     virtual status_t feedMoreTSData();
@@ -43,8 +44,6 @@
     virtual status_t getDuration(int64_t *durationUs);
     virtual status_t seekTo(int64_t seekTimeUs);
 
-    virtual uint32_t flags() const;
-
 protected:
     virtual ~HTTPLiveSource();
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 0736fbe..78b94ba 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -112,6 +112,7 @@
 
 NuPlayer::NuPlayer()
     : mUIDValid(false),
+      mSourceFlags(0),
       mVideoIsAVC(false),
       mAudioEOS(false),
       mVideoEOS(false),
@@ -142,7 +143,7 @@
     mDriver = driver;
 }
 
-void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
+void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
 
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
@@ -174,7 +175,7 @@
     return false;
 }
 
-void NuPlayer::setDataSource(
+void NuPlayer::setDataSourceAsync(
         const char *url, const KeyedVector<String8, String8> *headers) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
     size_t len = strlen(url);
@@ -199,7 +200,7 @@
     msg->post();
 }
 
-void NuPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
 
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
@@ -209,6 +210,10 @@
     msg->post();
 }
 
+void NuPlayer::prepareAsync() {
+    (new AMessage(kWhatPrepare, id()))->post();
+}
+
 void NuPlayer::setVideoSurfaceTextureAsync(
         const sp<IGraphicBufferProducer> &bufferProducer) {
     sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
@@ -287,6 +292,18 @@
             mSource = static_cast<Source *>(obj.get());
 
             looper()->registerHandler(mSource);
+
+            CHECK(mDriver != NULL);
+            sp<NuPlayerDriver> driver = mDriver.promote();
+            if (driver != NULL) {
+                driver->notifySetDataSourceCompleted(OK);
+            }
+            break;
+        }
+
+        case kWhatPrepare:
+        {
+            mSource->prepareAsync();
             break;
         }
 
@@ -403,9 +420,7 @@
                     && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
                 // This is the first time we've found anything playable.
 
-                uint32_t flags = mSource->flags();
-
-                if (flags & Source::FLAG_DYNAMIC_DURATION) {
+                if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
                     schedulePollDuration();
                 }
             }
@@ -730,7 +745,7 @@
 
         case kWhatSourceNotify:
         {
-            TRESPASS();  // TBD
+            onSourceNotify(msg);
             break;
         }
 
@@ -1233,8 +1248,76 @@
     }
 }
 
+void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
+    int32_t what;
+    CHECK(msg->findInt32("what", &what));
+
+    switch (what) {
+        case Source::kWhatPrepared:
+        {
+            sp<NuPlayerDriver> driver = mDriver.promote();
+            if (driver != NULL) {
+                driver->notifyPrepareCompleted(OK);
+            }
+            break;
+        }
+
+        case Source::kWhatFlagsChanged:
+        {
+            uint32_t flags;
+            CHECK(msg->findInt32("flags", (int32_t *)&flags));
+
+            if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                    && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
+                cancelPollDuration();
+            } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                    && (flags & Source::FLAG_DYNAMIC_DURATION)
+                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+                schedulePollDuration();
+            }
+
+            mSourceFlags = flags;
+            break;
+        }
+
+        case Source::kWhatVideoSizeChanged:
+        {
+            int32_t width, height;
+            CHECK(msg->findInt32("width", &width));
+            CHECK(msg->findInt32("height", &height));
+
+            notifyListener(MEDIA_SET_VIDEO_SIZE, width, height);
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
+void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) {
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatFlagsChanged);
+    notify->setInt32("flags", flags);
+    notify->post();
+}
+
+void NuPlayer::Source::notifyVideoSizeChanged(int32_t width, int32_t height) {
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatVideoSizeChanged);
+    notify->setInt32("width", width);
+    notify->setInt32("height", height);
+    notify->post();
+}
+
+void NuPlayer::Source::notifyPrepared() {
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatPrepared);
+    notify->post();
+}
+
 void NuPlayer::Source::onMessageReceived(const sp<AMessage> &msg) {
     TRESPASS();
 }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 0ff6089..50d0462 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -35,12 +35,14 @@
 
     void setDriver(const wp<NuPlayerDriver> &driver);
 
-    void setDataSource(const sp<IStreamSource> &source);
+    void setDataSourceAsync(const sp<IStreamSource> &source);
 
-    void setDataSource(
+    void setDataSourceAsync(
             const char *url, const KeyedVector<String8, String8> *headers);
 
-    void setDataSource(int fd, int64_t offset, int64_t length);
+    void setDataSourceAsync(int fd, int64_t offset, int64_t length);
+
+    void prepareAsync();
 
     void setVideoSurfaceTextureAsync(
             const sp<IGraphicBufferProducer> &bufferProducer);
@@ -82,6 +84,7 @@
 
     enum {
         kWhatSetDataSource              = '=DaS',
+        kWhatPrepare                    = 'prep',
         kWhatSetVideoNativeWindow       = '=NaW',
         kWhatSetAudioSink               = '=AuS',
         kWhatMoreDataQueued             = 'more',
@@ -102,6 +105,7 @@
     bool mUIDValid;
     uid_t mUID;
     sp<Source> mSource;
+    uint32_t mSourceFlags;
     sp<NativeWindowWrapper> mNativeWindow;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<Decoder> mVideoDecoder;
@@ -173,6 +177,8 @@
     void performScanSources();
     void performSetSurface(const sp<NativeWindowWrapper> &wrapper);
 
+    void onSourceNotify(const sp<AMessage> &msg);
+
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7043404..ab7b4e8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -21,21 +21,24 @@
 #include "NuPlayerDriver.h"
 
 #include "NuPlayer.h"
+#include "NuPlayerSource.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MetaData.h>
 
 namespace android {
 
 NuPlayerDriver::NuPlayerDriver()
-    : mResetInProgress(false),
+    : mState(STATE_IDLE),
+      mAsyncResult(UNKNOWN_ERROR),
       mSetSurfaceInProgress(false),
       mDurationUs(-1),
       mPositionUs(-1),
       mNumFramesTotal(0),
       mNumFramesDropped(0),
       mLooper(new ALooper),
-      mState(UNINITIALIZED),
+      mPlayerFlags(0),
       mAtEOS(false),
       mStartupSeekTimeUs(-1) {
     mLooper->setName("NuPlayerDriver Looper");
@@ -67,43 +70,76 @@
 
 status_t NuPlayerDriver::setDataSource(
         const char *url, const KeyedVector<String8, String8> *headers) {
-    CHECK_EQ((int)mState, (int)UNINITIALIZED);
+    Mutex::Autolock autoLock(mLock);
 
-    mPlayer->setDataSource(url, headers);
+    if (mState != STATE_IDLE) {
+        return INVALID_OPERATION;
+    }
 
-    mState = STOPPED;
+    mState = STATE_SET_DATASOURCE_PENDING;
 
-    return OK;
+    mPlayer->setDataSourceAsync(url, headers);
+
+    while (mState == STATE_SET_DATASOURCE_PENDING) {
+        mCondition.wait(mLock);
+    }
+
+    return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
-    CHECK_EQ((int)mState, (int)UNINITIALIZED);
+    Mutex::Autolock autoLock(mLock);
 
-    mPlayer->setDataSource(fd, offset, length);
+    if (mState != STATE_IDLE) {
+        return INVALID_OPERATION;
+    }
 
-    mState = STOPPED;
+    mState = STATE_SET_DATASOURCE_PENDING;
 
-    return OK;
+    mPlayer->setDataSourceAsync(fd, offset, length);
+
+    while (mState == STATE_SET_DATASOURCE_PENDING) {
+        mCondition.wait(mLock);
+    }
+
+    return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
-    CHECK_EQ((int)mState, (int)UNINITIALIZED);
+    Mutex::Autolock autoLock(mLock);
 
-    mPlayer->setDataSource(source);
+    if (mState != STATE_IDLE) {
+        return INVALID_OPERATION;
+    }
 
-    mState = STOPPED;
+    mState = STATE_SET_DATASOURCE_PENDING;
 
-    return OK;
+    mPlayer->setDataSourceAsync(source);
+
+    while (mState == STATE_SET_DATASOURCE_PENDING) {
+        mCondition.wait(mLock);
+    }
+
+    return mAsyncResult;
 }
 
 status_t NuPlayerDriver::setVideoSurfaceTexture(
         const sp<IGraphicBufferProducer> &bufferProducer) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mResetInProgress) {
+    if (mSetSurfaceInProgress) {
         return INVALID_OPERATION;
     }
 
+    switch (mState) {
+        case STATE_SET_DATASOURCE_PENDING:
+        case STATE_RESET_IN_PROGRESS:
+            return INVALID_OPERATION;
+
+        default:
+            break;
+    }
+
     mSetSurfaceInProgress = true;
 
     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
@@ -116,23 +152,55 @@
 }
 
 status_t NuPlayerDriver::prepare() {
-    sendEvent(MEDIA_SET_VIDEO_SIZE, 0, 0);
-    return OK;
+    Mutex::Autolock autoLock(mLock);
+    return prepare_l();
+}
+
+status_t NuPlayerDriver::prepare_l() {
+    switch (mState) {
+        case STATE_UNPREPARED:
+            mState = STATE_PREPARING;
+            mPlayer->prepareAsync();
+            while (mState == STATE_PREPARING) {
+                mCondition.wait(mLock);
+            }
+            return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
+        default:
+            return INVALID_OPERATION;
+    };
 }
 
 status_t NuPlayerDriver::prepareAsync() {
-    status_t err = prepare();
+    Mutex::Autolock autoLock(mLock);
 
-    notifyListener(MEDIA_PREPARED);
-
-    return err;
+    switch (mState) {
+        case STATE_UNPREPARED:
+            mState = STATE_PREPARING;
+            mPlayer->prepareAsync();
+            return OK;
+        default:
+            return INVALID_OPERATION;
+    };
 }
 
 status_t NuPlayerDriver::start() {
+    Mutex::Autolock autoLock(mLock);
+
     switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case STOPPED:
+        case STATE_UNPREPARED:
+        {
+            status_t err = prepare_l();
+
+            if (err != OK) {
+                return err;
+            }
+
+            CHECK_EQ(mState, STATE_PREPARED);
+
+            // fall through
+        }
+
+        case STATE_PREPARED:
         {
             mAtEOS = false;
             mPlayer->start();
@@ -146,21 +214,23 @@
 
                 mStartupSeekTimeUs = -1;
             }
-
             break;
         }
-        case PLAYING:
-            return OK;
-        default:
-        {
-            CHECK_EQ((int)mState, (int)PAUSED);
 
+        case STATE_RUNNING:
+            break;
+
+        case STATE_PAUSED:
+        {
             mPlayer->resume();
             break;
         }
+
+        default:
+            return INVALID_OPERATION;
     }
 
-    mState = PLAYING;
+    mState = STATE_RUNNING;
 
     return OK;
 }
@@ -170,43 +240,44 @@
 }
 
 status_t NuPlayerDriver::pause() {
+    Mutex::Autolock autoLock(mLock);
+
     switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case STOPPED:
+        case STATE_PAUSED:
+        case STATE_PREPARED:
             return OK;
-        case PLAYING:
+
+        case STATE_RUNNING:
             mPlayer->pause();
             break;
+
         default:
-        {
-            CHECK_EQ((int)mState, (int)PAUSED);
-            return OK;
-        }
+            return INVALID_OPERATION;
     }
 
-    mState = PAUSED;
+    mState = STATE_PAUSED;
 
     return OK;
 }
 
 bool NuPlayerDriver::isPlaying() {
-    return mState == PLAYING && !mAtEOS;
+    return mState == STATE_RUNNING && !mAtEOS;
 }
 
 status_t NuPlayerDriver::seekTo(int msec) {
+    Mutex::Autolock autoLock(mLock);
+
     int64_t seekTimeUs = msec * 1000ll;
 
     switch (mState) {
-        case UNINITIALIZED:
-            return INVALID_OPERATION;
-        case STOPPED:
+        case STATE_PREPARED:
         {
             mStartupSeekTimeUs = seekTimeUs;
             break;
         }
-        case PLAYING:
-        case PAUSED:
+
+        case STATE_RUNNING:
+        case STATE_PAUSED:
         {
             mAtEOS = false;
             mPlayer->seekToAsync(seekTimeUs);
@@ -214,8 +285,7 @@
         }
 
         default:
-            TRESPASS();
-            break;
+            return INVALID_OPERATION;
     }
 
     return OK;
@@ -247,17 +317,28 @@
 
 status_t NuPlayerDriver::reset() {
     Mutex::Autolock autoLock(mLock);
-    mResetInProgress = true;
 
+    switch (mState) {
+        case STATE_IDLE:
+            return OK;
+
+        case STATE_SET_DATASOURCE_PENDING:
+        case STATE_RESET_IN_PROGRESS:
+            return INVALID_OPERATION;
+
+        default:
+            break;
+    }
+
+    mState = STATE_RESET_IN_PROGRESS;
     mPlayer->resetAsync();
 
-    while (mResetInProgress) {
+    while (mState == STATE_RESET_IN_PROGRESS) {
         mCondition.wait(mLock);
     }
 
     mDurationUs = -1;
     mPositionUs = -1;
-    mState = UNINITIALIZED;
     mStartupSeekTimeUs = -1;
 
     return OK;
@@ -311,20 +392,45 @@
 
 status_t NuPlayerDriver::getMetadata(
         const media::Metadata::Filter& ids, Parcel *records) {
-    return INVALID_OPERATION;
+    Mutex::Autolock autoLock(mLock);
+
+    using media::Metadata;
+
+    Metadata meta(records);
+
+    meta.appendBool(
+            Metadata::kPauseAvailable,
+            mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
+
+    meta.appendBool(
+            Metadata::kSeekBackwardAvailable,
+            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
+
+    meta.appendBool(
+            Metadata::kSeekForwardAvailable,
+            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
+
+    meta.appendBool(
+            Metadata::kSeekAvailable,
+            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
+
+    return OK;
 }
 
 void NuPlayerDriver::notifyResetComplete() {
     Mutex::Autolock autoLock(mLock);
-    CHECK(mResetInProgress);
-    mResetInProgress = false;
+
+    CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
+    mState = STATE_IDLE;
     mCondition.broadcast();
 }
 
 void NuPlayerDriver::notifySetSurfaceComplete() {
     Mutex::Autolock autoLock(mLock);
+
     CHECK(mSetSurfaceInProgress);
     mSetSurfaceInProgress = false;
+
     mCondition.broadcast();
 }
 
@@ -376,4 +482,37 @@
     sendEvent(msg, ext1, ext2);
 }
 
+void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
+    Mutex::Autolock autoLock(mLock);
+
+    CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
+
+    mAsyncResult = err;
+    mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
+    mCondition.broadcast();
+}
+
+void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
+    Mutex::Autolock autoLock(mLock);
+
+    CHECK_EQ(mState, STATE_PREPARING);
+
+    mAsyncResult = err;
+
+    if (err == OK) {
+        notifyListener(MEDIA_PREPARED);
+        mState = STATE_PREPARED;
+    } else {
+        mState = STATE_UNPREPARED;
+    }
+
+    mCondition.broadcast();
+}
+
+void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
+    Mutex::Autolock autoLock(mLock);
+
+    mPlayerFlags = flags;
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 553c406..49b8ed2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -61,6 +61,8 @@
 
     virtual status_t dump(int fd, const Vector<String16> &args) const;
 
+    void notifySetDataSourceCompleted(status_t err);
+    void notifyPrepareCompleted(status_t err);
     void notifyResetComplete();
     void notifySetSurfaceComplete();
     void notifyDuration(int64_t durationUs);
@@ -68,17 +70,32 @@
     void notifySeekComplete();
     void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
     void notifyListener(int msg, int ext1 = 0, int ext2 = 0);
+    void notifyFlagsChanged(uint32_t flags);
 
 protected:
     virtual ~NuPlayerDriver();
 
 private:
+    enum State {
+        STATE_IDLE,
+        STATE_SET_DATASOURCE_PENDING,
+        STATE_UNPREPARED,
+        STATE_PREPARING,
+        STATE_PREPARED,
+        STATE_RUNNING,
+        STATE_PAUSED,
+        STATE_RESET_IN_PROGRESS,
+    };
+
     mutable Mutex mLock;
     Condition mCondition;
 
+    State mState;
+
+    status_t mAsyncResult;
+
     // The following are protected through "mLock"
     // >>>
-    bool mResetInProgress;
     bool mSetSurfaceInProgress;
     int64_t mDurationUs;
     int64_t mPositionUs;
@@ -88,19 +105,14 @@
 
     sp<ALooper> mLooper;
     sp<NuPlayer> mPlayer;
+    uint32_t mPlayerFlags;
 
-    enum State {
-        UNINITIALIZED,
-        STOPPED,
-        PLAYING,
-        PAUSED
-    };
-
-    State mState;
     bool mAtEOS;
 
     int64_t mStartupSeekTimeUs;
 
+    status_t prepare_l();
+
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayerDriver);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index a3201cf..53c7c12 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -25,11 +25,21 @@
 namespace android {
 
 struct ABuffer;
+struct MetaData;
 
 struct NuPlayer::Source : public AHandler {
     enum Flags {
-        FLAG_SEEKABLE           = 1,
-        FLAG_DYNAMIC_DURATION   = 2,
+        FLAG_CAN_PAUSE          = 1,
+        FLAG_CAN_SEEK_BACKWARD  = 2,  // the "10 sec back button"
+        FLAG_CAN_SEEK_FORWARD   = 4,  // the "10 sec forward button"
+        FLAG_CAN_SEEK           = 8,  // the "seek bar"
+        FLAG_DYNAMIC_DURATION   = 16,
+    };
+
+    enum {
+        kWhatPrepared,
+        kWhatFlagsChanged,
+        kWhatVideoSizeChanged,
     };
 
     // The provides message is used to notify the player about various
@@ -38,6 +48,8 @@
         : mNotify(notify) {
     }
 
+    virtual void prepareAsync() = 0;
+
     virtual void start() = 0;
     virtual void stop() {}
 
@@ -58,8 +70,6 @@
         return INVALID_OPERATION;
     }
 
-    virtual uint32_t flags() const = 0;
-
 protected:
     virtual ~Source() {}
 
@@ -69,6 +79,10 @@
 
     sp<AMessage> dupNotify() const { return mNotify->dup(); }
 
+    void notifyFlagsChanged(uint32_t flags);
+    void notifyVideoSizeChanged(int32_t width, int32_t height);
+    void notifyPrepared();
+
 private:
     sp<AMessage> mNotify;
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 3035589..e4d72d9 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -65,7 +65,7 @@
    mLooper->stop();
 }
 
-void NuPlayer::RTSPSource::start() {
+void NuPlayer::RTSPSource::prepareAsync() {
     if (mLooper == NULL) {
         mLooper = new ALooper;
         mLooper->setName("rtsp");
@@ -88,13 +88,27 @@
                 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
                 mUIDValid, mUID);
 
-        mSDPLoader->load(mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
+        mSDPLoader->load(
+                mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
     } else {
         mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
         mLooper->registerHandler(mHandler);
 
         mHandler->connect();
     }
+
+    notifyVideoSizeChanged(0, 0);
+
+    notifyFlagsChanged(
+            FLAG_CAN_PAUSE
+            | FLAG_CAN_SEEK_BACKWARD
+            | FLAG_CAN_SEEK_FORWARD
+            | FLAG_CAN_SEEK);
+
+    notifyPrepared();
+}
+
+void NuPlayer::RTSPSource::start() {
 }
 
 void NuPlayer::RTSPSource::stop() {
@@ -225,10 +239,6 @@
     mHandler->seek(seekTimeUs);
 }
 
-uint32_t NuPlayer::RTSPSource::flags() const {
-    return FLAG_SEEKABLE;
-}
-
 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
     if (msg->what() == kWhatDisconnect) {
         uint32_t replyID;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index b2a7dae..cbb6f90 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -40,6 +40,7 @@
             uid_t uid = 0,
             bool isSDP = false);
 
+    virtual void prepareAsync();
     virtual void start();
     virtual void stop();
 
@@ -50,8 +51,6 @@
     virtual status_t getDuration(int64_t *durationUs);
     virtual status_t seekTo(int64_t seekTimeUs);
 
-    virtual uint32_t flags() const;
-
     void onMessageReceived(const sp<AMessage> &msg);
 
 protected:
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index 9b04833..df03f86 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -43,6 +43,12 @@
 NuPlayer::StreamingSource::~StreamingSource() {
 }
 
+void NuPlayer::StreamingSource::prepareAsync() {
+    notifyVideoSizeChanged(0, 0);
+    notifyFlagsChanged(0);
+    notifyPrepared();
+}
+
 void NuPlayer::StreamingSource::start() {
     mStreamListener = new NuPlayerStreamListener(mSource, 0);
 
@@ -176,9 +182,5 @@
     return err;
 }
 
-uint32_t NuPlayer::StreamingSource::flags() const {
-    return 0;
-}
-
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
index dc616f7..80b061c 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.h
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -31,14 +31,13 @@
             const sp<AMessage> &notify,
             const sp<IStreamSource> &source);
 
+    virtual void prepareAsync();
     virtual void start();
 
     virtual status_t feedMoreTSData();
 
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
 
-    virtual uint32_t flags() const;
-
 protected:
     virtual ~StreamingSource();
 
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
index d659b73..d31d947 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
@@ -117,6 +117,12 @@
 MP4Source::~MP4Source() {
 }
 
+void MP4Source::prepareAsync() {
+    notifyVideoSizeChanged(0, 0);
+    notifyFlagsChanged(0);
+    notifyPrepared();
+}
+
 void MP4Source::start() {
     mLooper->start(false /* runOnCallingThread */);
     mParser->start(new StreamSource(mSource));
@@ -135,8 +141,4 @@
     return mParser->dequeueAccessUnit(audio, accessUnit);
 }
 
-uint32_t MP4Source::flags() const {
-    return 0;
-}
-
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
index b16a111..a6ef622 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
@@ -26,6 +26,7 @@
 struct MP4Source : public NuPlayer::Source {
     MP4Source(const sp<AMessage> &notify, const sp<IStreamSource> &source);
 
+    virtual void prepareAsync();
     virtual void start();
 
     virtual status_t feedMoreTSData();
@@ -35,8 +36,6 @@
     virtual status_t dequeueAccessUnit(
             bool audio, sp<ABuffer> *accessUnit);
 
-    virtual uint32_t flags() const;
-
 protected:
     virtual ~MP4Source();