MediaPlayer2: initial code for playlist support

Test: MediaPlayer2 plays
Bug: 63934228
Change-Id: If63c97e225759108a30bb58ab0870569e0878ade
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);