Support for a "preparation" state that can take care of lengthy
operations in NuPlayer and its sources. Sources also can publish their
flags now and the mediaplayer UI will be able to pick up on these.
Change-Id: I4f2b7e5d105dcb4b6c9132cd0e8799efa0c6a14b
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