MediaPlayer2: initial code for playlist support

Test: MediaPlayer2 plays
Bug: 63934228
Change-Id: If63c97e225759108a30bb58ab0870569e0878ade
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.cpp b/media/libmediaplayer2/MediaPlayer2Manager.cpp
index 44df2ac..39b102c 100644
--- a/media/libmediaplayer2/MediaPlayer2Manager.cpp
+++ b/media/libmediaplayer2/MediaPlayer2Manager.cpp
@@ -606,6 +606,39 @@
     return status;
 }
 
+status_t MediaPlayer2Manager::Client::prepareNextDataSource(
+        const sp<DataSourceDesc> &dsd) {
+    sp<MediaPlayer2Interface> p = getPlayer();
+    if (p == NULL) {
+        return NO_INIT;
+    }
+
+    if (dsd == NULL) {
+        return BAD_VALUE;
+    }
+
+    status_t status = p->prepareNextDataSource(dsd);
+    if (status != OK) {
+        ALOGE("prepareNextDataSource error: %d", status);
+    }
+
+    return status;
+}
+
+status_t MediaPlayer2Manager::Client::playNextDataSource(int64_t srcId) {
+    sp<MediaPlayer2Interface> p = getPlayer();
+    if (p == NULL) {
+        return NO_INIT;
+    }
+
+    status_t status = p->playNextDataSource(srcId);
+    if (status != OK) {
+        ALOGE("playNextDataSource error: %d", status);
+    }
+
+    return status;
+}
+
 void MediaPlayer2Manager::Client::disconnectNativeWindow_l() {
     if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
         status_t err = native_window_api_disconnect(
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.h b/media/libmediaplayer2/MediaPlayer2Manager.h
index 7e6f0de..52bb9c6 100644
--- a/media/libmediaplayer2/MediaPlayer2Manager.h
+++ b/media/libmediaplayer2/MediaPlayer2Manager.h
@@ -274,7 +274,9 @@
         virtual status_t        getParameter(int key, Parcel *reply);
         virtual status_t        setNextPlayer(const sp<MediaPlayer2Engine>& player);
 
-        virtual status_t        setDataSource(const sp<DataSourceDesc> &dsd);
+        virtual status_t        setDataSource(const sp<DataSourceDesc> &dsd) override;
+        virtual status_t        prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
+        virtual status_t        playNextDataSource(int64_t srcId) override;
 
         static  void            notify(const wp<MediaPlayer2Engine> &listener, int64_t srcId,
                                        int msg, int ext1, int ext2, const Parcel *obj);
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
index 2d1a24b..749d83c 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
@@ -48,6 +48,8 @@
     virtual void            disconnect() = 0;
 
     virtual status_t        setDataSource(const sp<DataSourceDesc>& source) = 0;
+    virtual status_t        prepareNextDataSource(const sp<DataSourceDesc>& source) = 0;
+    virtual status_t        playNextDataSource(int64_t srcId) = 0;
     virtual status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
     virtual status_t        getBufferingSettings(
                                     BufferingSettings* buffering /* nonnull */) = 0;
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index b1cdf96..c0c490b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -150,9 +150,11 @@
 
     virtual void        setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
 
-    virtual status_t    setDataSource(const sp<DataSourceDesc>& /* dsd */) {
-        return INVALID_OPERATION;
-    }
+    virtual status_t    setDataSource(const sp<DataSourceDesc> &dsd) = 0;
+
+    virtual status_t    prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
+
+    virtual status_t    playNextDataSource(int64_t srcId) = 0;
 
     // pass the buffered native window to the media player service
     virtual status_t    setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
@@ -166,7 +168,6 @@
         return OK;
     }
 
-    virtual status_t    prepare() = 0;
     virtual status_t    prepareAsync() = 0;
     virtual status_t    start() = 0;
     virtual status_t    stop() = 0;
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index e9d6f84..0afef1e 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -114,7 +114,24 @@
     // player, which just completed playback
     MEDIA2_INFO_STARTED_AS_NEXT = 2,
     // The player just pushed the very first video frame for rendering
-    MEDIA2_INFO_RENDERING_START = 3,
+    MEDIA2_INFO_VIDEO_RENDERING_START = 3,
+    // The player just pushed the very first audio frame for rendering
+    MEDIA2_INFO_AUDIO_RENDERING_START = 4,
+    // The player just completed the playback of this data source
+    MEDIA2_INFO_PLAYBACK_COMPLETE = 5,
+    // The player just completed the playback of the full play list
+    MEDIA2_INFO_PLAYLIST_END = 6,
+
+    //1xx
+    // The player just prepared a data source.
+    MEDIA2_INFO_PREPARED = 100,
+    // The player just completed a call play().
+    MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
+    // The player just completed a call pause().
+    MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
+    // The player just completed a call seekTo.
+    MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
+
     // 7xx
     // The video is too complex for the decoder: it can't decode frames fast
     // enough. Possibly only the audio plays fine at this stage.
@@ -206,11 +223,12 @@
 
             status_t        getSrcId(int64_t *srcId);
             status_t        setDataSource(const sp<DataSourceDesc> &dsd);
+            status_t        prepareNextDataSource(const sp<DataSourceDesc> &dsd);
+            status_t        playNextDataSource(int64_t srcId);
             status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
             status_t        setListener(const sp<MediaPlayer2Listener>& listener);
             status_t        getBufferingSettings(BufferingSettings* buffering /* nonnull */);
             status_t        setBufferingSettings(const BufferingSettings& buffering);
-            status_t        prepare();
             status_t        prepareAsync();
             status_t        start();
             status_t        stop();
@@ -271,7 +289,6 @@
     thread_id_t                 mLockThreadId;
     Mutex                       mLock;
     Mutex                       mNotifyLock;
-    Condition                   mSignal;
     sp<MediaPlayer2Listener>    mListener;
     void*                       mCookie;
     media_player2_states        mCurrentState;
@@ -279,8 +296,6 @@
     MediaPlayer2SeekMode        mCurrentSeekMode;
     int                         mSeekPosition;
     MediaPlayer2SeekMode        mSeekMode;
-    bool                        mPrepareSync;
-    status_t                    mPrepareStatus;
     audio_stream_type_t         mStreamType;
     Parcel*                     mAudioAttributesParcel;
     bool                        mLoop;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index ab30273..75d06b8 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -63,8 +63,6 @@
     mSeekPosition = -1;
     mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER2_IDLE;
-    mPrepareSync = false;
-    mPrepareStatus = NO_ERROR;
     mLoop = false;
     mLeftVolume = mRightVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
@@ -176,6 +174,32 @@
     return err;
 }
 
+status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
+    if (dsd == NULL) {
+        return BAD_VALUE;
+    }
+    ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
+
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != NULL) {
+        return mPlayer->prepareNextDataSource(dsd);
+    }
+    ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
+    ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
+
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != NULL) {
+        mSrcId = srcId;
+        return mPlayer->playNextDataSource(srcId);
+    }
+    ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+    return INVALID_OPERATION;
+}
+
 status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply)
 {
     Mutex::Autolock _l(mLock);
@@ -256,35 +280,6 @@
     return INVALID_OPERATION;
 }
 
-// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
-// one defined in the Android framework and one provided by the implementation
-// that generated the error. The sync version of prepare returns only 1 error
-// code.
-status_t MediaPlayer2::prepare()
-{
-    ALOGV("prepare");
-    Mutex::Autolock _l(mLock);
-    mLockThreadId = getThreadId();
-    if (mPrepareSync) {
-        mLockThreadId = 0;
-        return -EALREADY;
-    }
-    mPrepareSync = true;
-    status_t ret = prepareAsync_l();
-    if (ret != NO_ERROR) {
-        mLockThreadId = 0;
-        return ret;
-    }
-
-    if (mPrepareSync) {
-        mSignal.wait(mLock);  // wait for prepare done
-        mPrepareSync = false;
-    }
-    ALOGV("prepare complete - status=%d", mPrepareStatus);
-    mLockThreadId = 0;
-    return mPrepareStatus;
-}
-
 status_t MediaPlayer2::prepareAsync()
 {
     ALOGV("prepareAsync");
@@ -576,7 +571,6 @@
 {
     mLoop = false;
     if (mCurrentState == MEDIA_PLAYER2_IDLE) return NO_ERROR;
-    mPrepareSync = false;
     if (mPlayer != 0) {
         status_t ret = mPlayer->reset();
         if (ret != NO_ERROR) {
@@ -808,12 +802,6 @@
     case MEDIA2_PREPARED:
         ALOGV("MediaPlayer2::notify() prepared");
         mCurrentState = MEDIA_PLAYER2_PREPARED;
-        if (mPrepareSync) {
-            ALOGV("signal application thread");
-            mPrepareSync = false;
-            mPrepareStatus = NO_ERROR;
-            mSignal.signal();
-        }
         break;
     case MEDIA2_DRM_INFO:
         ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
@@ -834,14 +822,6 @@
         // ext2: Implementation dependant error code.
         ALOGE("error (%d, %d)", ext1, ext2);
         mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
-        if (mPrepareSync)
-        {
-            ALOGV("signal application thread");
-            mPrepareSync = false;
-            mPrepareStatus = ext1;
-            mSignal.signal();
-            send = false;
-        }
         break;
     case MEDIA2_INFO:
         // ext1: Media framework error code.
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 462a904..38d107d 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -423,6 +423,14 @@
     msg->post();
 }
 
+void NuPlayer2::playNextDataSource(int64_t srcId) {
+    disconnectSource();
+
+    sp<AMessage> msg = new AMessage(kWhatPlayNextDataSource, this);
+    msg->setInt64("srcId", srcId);
+    msg->post();
+}
+
 status_t NuPlayer2::getBufferingSettings(
         BufferingSettings *buffering /* nonnull */) {
     sp<AMessage> msg = new AMessage(kWhatGetBufferingSettings, this);
@@ -538,6 +546,11 @@
 }
 
 void NuPlayer2::resetAsync() {
+    disconnectSource();
+    (new AMessage(kWhatReset, this))->post();
+}
+
+void NuPlayer2::disconnectSource() {
     sp<Source> source;
     {
         Mutex::Autolock autoLock(mSourceLock);
@@ -554,7 +567,6 @@
         source->disconnect();
     }
 
-    (new AMessage(kWhatReset, this))->post();
 }
 
 status_t NuPlayer2::notifyAt(int64_t mediaTimeUs) {
@@ -671,6 +683,32 @@
             break;
         }
 
+        case kWhatPlayNextDataSource:
+        {
+            ALOGV("kWhatPlayNextDataSource");
+            int64_t srcId;
+            CHECK(msg->findInt64("srcId", &srcId));
+            if (srcId != mNextSrcId) {
+                notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
+                return;
+            }
+
+            mResetting = true;
+            stopPlaybackTimer("kWhatPlayNextDataSource");
+            stopRebufferingTimer(true);
+
+            mDeferredActions.push_back(
+                    new FlushDecoderAction(
+                        FLUSH_CMD_SHUTDOWN /* audio */,
+                        FLUSH_CMD_SHUTDOWN /* video */));
+
+            mDeferredActions.push_back(
+                    new SimpleAction(&NuPlayer2::performPlayNextDataSource));
+
+            processDeferredActions();
+            break;
+        }
+
         case kWhatGetBufferingSettings:
         {
             sp<AReplyToken> replyID;
@@ -1382,7 +1420,7 @@
                 handleFlushComplete(audio, false /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
-                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_RENDERING_START, 0);
+                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
                 notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
@@ -2403,6 +2441,67 @@
     mIsDrmProtected = false;
 }
 
+void NuPlayer2::performPlayNextDataSource() {
+    ALOGV("performPlayNextDataSource");
+
+    CHECK(mAudioDecoder == NULL);
+    CHECK(mVideoDecoder == NULL);
+
+    stopPlaybackTimer("performPlayNextDataSource");
+    stopRebufferingTimer(true);
+
+    cancelPollDuration();
+
+    ++mScanSourcesGeneration;
+    mScanSourcesPending = false;
+
+    ++mRendererGeneration;
+
+    if (mSource != NULL) {
+        mSource->stop();
+    }
+
+    long previousSrcId;
+    {
+        Mutex::Autolock autoLock(mSourceLock);
+        mSource = mNextSource;
+        mNextSource = NULL;
+        previousSrcId = mSrcId;
+        mSrcId = mNextSrcId;
+        ++mNextSrcId;  // to distinguish the two sources.
+    }
+
+    if (mDriver != NULL) {
+        sp<NuPlayer2Driver> driver = mDriver.promote();
+        if (driver != NULL) {
+            notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAYBACK_COMPLETE, 0);
+            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0);
+        }
+    }
+
+    mStarted = false;
+    mPrepared = true;  // TODO: what if it's not prepared
+    mResetting = false;
+    mSourceStarted = false;
+
+    // Modular DRM
+    if (mCrypto != NULL) {
+        // decoders will be flushed before this so their mCrypto would go away on their own
+        // TODO change to ALOGV
+        ALOGD("performReset mCrypto: %p", mCrypto.get());
+        mCrypto.clear();
+    }
+    mIsDrmProtected = false;
+
+    if (mRenderer != NULL) {
+        mRenderer->resume();
+    }
+
+    onStart();
+    mPausedByClient = false;
+    notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+}
+
 void NuPlayer2::performScanSources() {
     ALOGV("performScanSources");
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e7b774c..96f85f9 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -44,6 +44,7 @@
 
     void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
     void prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd);
+    void playNextDataSource(int64_t srcId);
 
     status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
     status_t setBufferingSettings(const BufferingSettings& buffering);
@@ -121,6 +122,7 @@
         kWhatSetDataSource              = '=DaS',
         kWhatPrepare                    = 'prep',
         kWhatPrepareNextDataSource      = 'pNDS',
+        kWhatPlayNextDataSource         = 'plNS',
         kWhatSetVideoSurface            = '=VSu',
         kWhatSetAudioSink               = '=AuS',
         kWhatMoreDataQueued             = 'more',
@@ -269,6 +271,8 @@
         mFlushComplete[1][1] = false;
     }
 
+    void disconnectSource();
+
     status_t createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
                                    sp<Source> *source,
                                    DATA_SOURCE_TYPE *dataSourceType);
@@ -314,6 +318,7 @@
     void performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
     void performDecoderFlush(FlushCommand audio, FlushCommand video);
     void performReset();
+    void performPlayNextDataSource();
     void performScanSources();
     void performSetSurface(const sp<ANativeWindowWrapper> &nw);
     void performResumeDecoders(bool needNotify);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 60a07a3..ca08e79 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -107,7 +107,6 @@
 
 NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid)
     : mState(STATE_IDLE),
-      mIsAsyncPrepare(false),
       mAsyncResult(UNKNOWN_ERROR),
       mSrcId(0),
       mSetSurfaceInProgress(false),
@@ -174,7 +173,7 @@
 }
 
 status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
-    ALOGV("setDataSource(%p) callback source", this);
+    ALOGV("setDataSource(%p)", this);
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
@@ -193,6 +192,25 @@
     return mAsyncResult;
 }
 
+status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
+    ALOGV("prepareNextDataSource(%p)", this);
+    Mutex::Autolock autoLock(mLock);
+
+    mPlayer->prepareNextDataSourceAsync(dsd);
+
+    return OK;
+}
+
+status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
+    ALOGV("playNextDataSource(%p)", this);
+    Mutex::Autolock autoLock(mLock);
+
+    mSrcId = srcId;
+    mPlayer->playNextDataSource(srcId);
+
+    return OK;
+}
+
 status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
     ALOGV("setVideoSurfaceTexture(%p)", this);
     Mutex::Autolock autoLock(mLock);
@@ -245,42 +263,6 @@
     return mPlayer->setBufferingSettings(buffering);
 }
 
-status_t NuPlayer2Driver::prepare() {
-    ALOGV("prepare(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-    return prepare_l();
-}
-
-status_t NuPlayer2Driver::prepare_l() {
-    switch (mState) {
-        case STATE_UNPREPARED:
-            mState = STATE_PREPARING;
-
-            // Make sure we're not posting any notifications, success or
-            // failure information is only communicated through our result
-            // code.
-            mIsAsyncPrepare = false;
-            mPlayer->prepareAsync();
-            while (mState == STATE_PREPARING) {
-                mCondition.wait(mLock);
-            }
-            return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
-        case STATE_STOPPED:
-            // this is really just paused. handle as seek to start
-            mAtEOS = false;
-            mState = STATE_STOPPED_AND_PREPARING;
-            mIsAsyncPrepare = false;
-            mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
-                    true /* needNotify */);
-            while (mState == STATE_STOPPED_AND_PREPARING) {
-                mCondition.wait(mLock);
-            }
-            return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
-        default:
-            return INVALID_OPERATION;
-    };
-}
-
 status_t NuPlayer2Driver::prepareAsync() {
     ALOGV("prepareAsync(%p)", this);
     Mutex::Autolock autoLock(mLock);
@@ -288,14 +270,12 @@
     switch (mState) {
         case STATE_UNPREPARED:
             mState = STATE_PREPARING;
-            mIsAsyncPrepare = true;
             mPlayer->prepareAsync();
             return OK;
         case STATE_STOPPED:
             // this is really just paused. handle as seek to start
             mAtEOS = false;
             mState = STATE_STOPPED_AND_PREPARING;
-            mIsAsyncPrepare = true;
             mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
                     true /* needNotify */);
             return OK;
@@ -312,19 +292,6 @@
 
 status_t NuPlayer2Driver::start_l() {
     switch (mState) {
-        case STATE_UNPREPARED:
-        {
-            status_t err = prepare_l();
-
-            if (err != OK) {
-                return err;
-            }
-
-            CHECK_EQ(mState, STATE_PREPARED);
-
-            // fall through
-        }
-
         case STATE_PAUSED:
         case STATE_STOPPED_AND_PREPARED:
         case STATE_PREPARED:
@@ -626,8 +593,6 @@
 
         case STATE_PREPARING:
         {
-            CHECK(mIsAsyncPrepare);
-
             notifyListener_l(mSrcId, MEDIA2_PREPARED);
             break;
         }
@@ -824,10 +789,6 @@
         wasSeeking = false;
         mState = STATE_STOPPED_AND_PREPARED;
         mCondition.broadcast();
-        if (!mIsAsyncPrepare) {
-            // if we are preparing synchronously, no need to notify listener
-            return;
-        }
     } else if (mState == STATE_STOPPED) {
         // no need to notify listener
         return;
@@ -947,58 +908,60 @@
     ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
             this, (long long)srcId, msg, ext1, ext2,
             (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
-    switch (msg) {
-        case MEDIA2_PLAYBACK_COMPLETE:
-        {
-            if (mState != STATE_RESET_IN_PROGRESS) {
-                if (mAutoLoop) {
-                    audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
-                    if (mAudioSink != NULL) {
-                        streamType = mAudioSink->getAudioStreamType();
+    if (srcId == mSrcId) {
+        switch (msg) {
+            case MEDIA2_PLAYBACK_COMPLETE:
+            {
+                if (mState != STATE_RESET_IN_PROGRESS) {
+                    if (mAutoLoop) {
+                        audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
+                        if (mAudioSink != NULL) {
+                            streamType = mAudioSink->getAudioStreamType();
+                        }
+                        if (streamType == AUDIO_STREAM_NOTIFICATION) {
+                            ALOGW("disabling auto-loop for notification");
+                            mAutoLoop = false;
+                        }
                     }
-                    if (streamType == AUDIO_STREAM_NOTIFICATION) {
-                        ALOGW("disabling auto-loop for notification");
-                        mAutoLoop = false;
+                    if (mLooping || mAutoLoop) {
+                        mPlayer->seekToAsync(0);
+                        if (mAudioSink != NULL) {
+                            // The renderer has stopped the sink at the end in order to play out
+                            // the last little bit of audio. In looping mode, we need to restart it.
+                            mAudioSink->start();
+                        }
+                        // don't send completion event when looping
+                        return;
                     }
-                }
-                if (mLooping || mAutoLoop) {
-                    mPlayer->seekToAsync(0);
-                    if (mAudioSink != NULL) {
-                        // The renderer has stopped the sink at the end in order to play out
-                        // the last little bit of audio. If we're looping, we need to restart it.
-                        mAudioSink->start();
+                    if (property_get_bool("persist.debug.sf.stats", false)) {
+                        Vector<String16> args;
+                        dump(-1, args);
                     }
-                    // don't send completion event when looping
-                    return;
+                    mPlayer->pause();
+                    mState = STATE_PAUSED;
                 }
-                if (property_get_bool("persist.debug.sf.stats", false)) {
-                    Vector<String16> args;
-                    dump(-1, args);
-                }
-                mPlayer->pause();
-                mState = STATE_PAUSED;
+                // fall through
             }
-            // fall through
-        }
 
-        case MEDIA2_ERROR:
-        {
-            // when we have an error, add it to the analytics for this playback.
-            // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
-            // [test against msg is due to fall through from previous switch value]
-            if (msg == MEDIA2_ERROR) {
-                mAnalyticsItem->setInt32(kPlayerError, ext1);
-                if (ext2 != 0) {
-                    mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
+            case MEDIA2_ERROR:
+            {
+                // when we have an error, add it to the analytics for this playback.
+                // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
+                // [test against msg is due to fall through from previous switch value]
+                if (msg == MEDIA2_ERROR) {
+                    mAnalyticsItem->setInt32(kPlayerError, ext1);
+                    if (ext2 != 0) {
+                        mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
+                    }
+                    mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
                 }
-                mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
+                mAtEOS = true;
+                break;
             }
-            mAtEOS = true;
-            break;
-        }
 
-        default:
-            break;
+            default:
+                break;
+        }
     }
 
     sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
@@ -1025,6 +988,15 @@
 
     Mutex::Autolock autoLock(mLock);
 
+    if (srcId != mSrcId) {
+        if (err == OK) {
+            notifyListener_l(srcId, MEDIA2_PREPARED);
+        } else {
+            notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+        }
+        return;
+    }
+
     if (mState != STATE_PREPARING) {
         // We were preparing asynchronously when the client called
         // reset(), we sent a premature "prepared" notification and
@@ -1041,14 +1013,10 @@
         // update state before notifying client, so that if client calls back into NuPlayer2Driver
         // in response, NuPlayer2Driver has the right state
         mState = STATE_PREPARED;
-        if (mIsAsyncPrepare) {
-            notifyListener_l(srcId, MEDIA2_PREPARED);
-        }
+        notifyListener_l(srcId, MEDIA2_PREPARED);
     } else {
         mState = STATE_UNPREPARED;
-        if (mIsAsyncPrepare) {
-            notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
-        }
+        notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
     }
 
     sp<MetaData> meta = mPlayer->getFileMeta();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 4c57cfd..502a2cc 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -28,17 +28,18 @@
 struct NuPlayer2Driver : public MediaPlayer2Interface {
     explicit NuPlayer2Driver(pid_t pid, uid_t uid);
 
-    virtual status_t initCheck();
+    virtual status_t initCheck() override;
 
     virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
+    virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
+    virtual status_t playNextDataSource(int64_t srcId) override;
 
-    virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww);
+    virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) override;
 
     virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual status_t prepare();
     virtual status_t prepareAsync();
     virtual status_t start();
     virtual status_t stop();
@@ -114,7 +115,6 @@
 
     State mState;
 
-    bool mIsAsyncPrepare;
     status_t mAsyncResult;
 
     // The following are protected through "mLock"
@@ -147,7 +147,6 @@
     void updateMetrics(const char *where);
     void logMetrics(const char *where);
 
-    status_t prepare_l();
     status_t start_l();
     void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
                           const Parcel *in = NULL);