MediaPlayer2: initial code for playlist support

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