summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp')
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp180
1 files changed, 159 insertions, 21 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b9651a1..7dd54c1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -37,11 +37,14 @@ NuPlayerDriver::NuPlayerDriver()
mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
+ mNotifyTimeRealUs(-1),
+ mPauseStartedTimeUs(-1),
mNumFramesTotal(0),
mNumFramesDropped(0),
mLooper(new ALooper),
mPlayerFlags(0),
mAtEOS(false),
+ mLooping(false),
mStartupSeekTimeUs(-1) {
mLooper->setName("NuPlayerDriver Looper");
@@ -71,16 +74,19 @@ status_t NuPlayerDriver::setUID(uid_t uid) {
}
status_t NuPlayerDriver::setDataSource(
- const char *url, const KeyedVector<String8, String8> *headers) {
+ const sp<IMediaHTTPService> &httpService,
+ const char *url,
+ const KeyedVector<String8, String8> *headers) {
Mutex::Autolock autoLock(mLock);
+ ALOGV("setDataSource: url=%s", url);
if (mState != STATE_IDLE) {
return INVALID_OPERATION;
}
mState = STATE_SET_DATASOURCE_PENDING;
- mPlayer->setDataSourceAsync(url, headers);
+ mPlayer->setDataSourceAsync(httpService, url, headers);
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
@@ -92,6 +98,7 @@ status_t NuPlayerDriver::setDataSource(
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
Mutex::Autolock autoLock(mLock);
+ ALOGV("setDataSource: fd=%d", fd);
if (mState != STATE_IDLE) {
return INVALID_OPERATION;
}
@@ -110,6 +117,7 @@ status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
Mutex::Autolock autoLock(mLock);
+ ALOGV("setDataSource: stream source");
if (mState != STATE_IDLE) {
return INVALID_OPERATION;
}
@@ -172,6 +180,16 @@ status_t NuPlayerDriver::prepare_l() {
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);
+ while (mState == STATE_STOPPED_AND_PREPARING) {
+ mCondition.wait(mLock);
+ }
+ return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
default:
return INVALID_OPERATION;
};
@@ -186,6 +204,13 @@ status_t NuPlayerDriver::prepareAsync() {
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);
+ return OK;
default:
return INVALID_OPERATION;
};
@@ -215,7 +240,7 @@ status_t NuPlayerDriver::start() {
if (mStartupSeekTimeUs >= 0) {
if (mStartupSeekTimeUs == 0) {
- notifySeekComplete();
+ notifySeekComplete_l();
} else {
mPlayer->seekToAsync(mStartupSeekTimeUs);
}
@@ -226,11 +251,20 @@ status_t NuPlayerDriver::start() {
}
case STATE_RUNNING:
+ {
+ if (mAtEOS) {
+ mPlayer->seekToAsync(0);
+ mAtEOS = false;
+ mPositionUs = -1;
+ }
break;
+ }
case STATE_PAUSED:
+ case STATE_STOPPED_AND_PREPARED:
{
mPlayer->resume();
+ mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs;
break;
}
@@ -239,12 +273,37 @@ status_t NuPlayerDriver::start() {
}
mState = STATE_RUNNING;
+ mPauseStartedTimeUs = -1;
return OK;
}
status_t NuPlayerDriver::stop() {
- return pause();
+ Mutex::Autolock autoLock(mLock);
+
+ switch (mState) {
+ case STATE_RUNNING:
+ mPlayer->pause();
+ // fall through
+
+ case STATE_PAUSED:
+ mState = STATE_STOPPED;
+ notifyListener_l(MEDIA_STOPPED);
+ break;
+
+ case STATE_PREPARED:
+ case STATE_STOPPED:
+ case STATE_STOPPED_AND_PREPARING:
+ case STATE_STOPPED_AND_PREPARED:
+ mState = STATE_STOPPED;
+ break;
+
+ default:
+ return INVALID_OPERATION;
+ }
+ setPauseStartedTimeIfNeeded();
+
+ return OK;
}
status_t NuPlayerDriver::pause() {
@@ -256,7 +315,9 @@ status_t NuPlayerDriver::pause() {
return OK;
case STATE_RUNNING:
- notifyListener(MEDIA_PAUSED);
+ setPauseStartedTimeIfNeeded();
+ mState = STATE_PAUSED;
+ notifyListener_l(MEDIA_PAUSED);
mPlayer->pause();
break;
@@ -264,8 +325,6 @@ status_t NuPlayerDriver::pause() {
return INVALID_OPERATION;
}
- mState = STATE_PAUSED;
-
return OK;
}
@@ -282,6 +341,10 @@ status_t NuPlayerDriver::seekTo(int msec) {
case STATE_PREPARED:
{
mStartupSeekTimeUs = seekTimeUs;
+ // pretend that the seek completed. It will actually happen when starting playback.
+ // TODO: actually perform the seek here, so the player is ready to go at the new
+ // location
+ notifySeekComplete_l();
break;
}
@@ -290,7 +353,7 @@ status_t NuPlayerDriver::seekTo(int msec) {
{
mAtEOS = false;
// seeks can take a while, so we essentially paused
- notifyListener(MEDIA_PAUSED);
+ notifyListener_l(MEDIA_PAUSED);
mPlayer->seekToAsync(seekTimeUs);
break;
}
@@ -299,6 +362,8 @@ status_t NuPlayerDriver::seekTo(int msec) {
return INVALID_OPERATION;
}
+ mPositionUs = seekTimeUs;
+ mNotifyTimeRealUs = -1;
return OK;
}
@@ -307,8 +372,12 @@ status_t NuPlayerDriver::getCurrentPosition(int *msec) {
if (mPositionUs < 0) {
*msec = 0;
+ } else if (mNotifyTimeRealUs == -1) {
+ *msec = mPositionUs / 1000;
} else {
- *msec = (mPositionUs + 500ll) / 1000;
+ int64_t nowUs =
+ (isPlaying() ? ALooper::GetNowUs() : mPauseStartedTimeUs);
+ *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000;
}
return OK;
@@ -341,7 +410,7 @@ status_t NuPlayerDriver::reset() {
{
CHECK(mIsAsyncPrepare);
- notifyListener(MEDIA_PREPARED);
+ notifyListener_l(MEDIA_PREPARED);
break;
}
@@ -349,7 +418,9 @@ status_t NuPlayerDriver::reset() {
break;
}
- notifyListener(MEDIA_STOPPED);
+ if (mState != STATE_STOPPED) {
+ notifyListener_l(MEDIA_STOPPED);
+ }
mState = STATE_RESET_IN_PROGRESS;
mPlayer->resetAsync();
@@ -361,12 +432,14 @@ status_t NuPlayerDriver::reset() {
mDurationUs = -1;
mPositionUs = -1;
mStartupSeekTimeUs = -1;
+ mLooping = false;
return OK;
}
-status_t NuPlayerDriver::setLooping(int /* loop */) {
- return INVALID_OPERATION;
+status_t NuPlayerDriver::setLooping(int loop) {
+ mLooping = loop != 0;
+ return OK;
}
player_type NuPlayerDriver::playerType() {
@@ -410,6 +483,12 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
return mPlayer->selectTrack(trackIndex, false /* select */);
}
+ case INVOKE_ID_GET_SELECTED_TRACK:
+ {
+ int32_t type = request.readInt32();
+ return mPlayer->getSelectedTrack(type, reply);
+ }
+
default:
{
return INVALID_OPERATION;
@@ -481,11 +560,32 @@ void NuPlayerDriver::notifyDuration(int64_t durationUs) {
void NuPlayerDriver::notifyPosition(int64_t positionUs) {
Mutex::Autolock autoLock(mLock);
- mPositionUs = positionUs;
+ if (isPlaying()) {
+ mPositionUs = positionUs;
+ mNotifyTimeRealUs = ALooper::GetNowUs();
+ }
}
void NuPlayerDriver::notifySeekComplete() {
- notifyListener(MEDIA_SEEK_COMPLETE);
+ Mutex::Autolock autoLock(mLock);
+ notifySeekComplete_l();
+}
+
+void NuPlayerDriver::notifySeekComplete_l() {
+ bool wasSeeking = true;
+ if (mState == STATE_STOPPED_AND_PREPARING) {
+ 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;
+ }
+ notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
}
void NuPlayerDriver::notifyFrameStats(
@@ -517,11 +617,41 @@ status_t NuPlayerDriver::dump(
void NuPlayerDriver::notifyListener(
int msg, int ext1, int ext2, const Parcel *in) {
- if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) {
- mAtEOS = true;
+ Mutex::Autolock autoLock(mLock);
+ notifyListener_l(msg, ext1, ext2, in);
+}
+
+void NuPlayerDriver::notifyListener_l(
+ int msg, int ext1, int ext2, const Parcel *in) {
+ switch (msg) {
+ case MEDIA_PLAYBACK_COMPLETE:
+ {
+ if (mState != STATE_RESET_IN_PROGRESS) {
+ if (mLooping) {
+ mPlayer->seekToAsync(0);
+ break;
+ }
+
+ mPlayer->pause();
+ mState = STATE_PAUSED;
+ }
+ // fall through
+ }
+
+ case MEDIA_ERROR:
+ {
+ mAtEOS = true;
+ setPauseStartedTimeIfNeeded();
+ break;
+ }
+
+ default:
+ break;
}
+ mLock.unlock();
sendEvent(msg, ext1, ext2, in);
+ mLock.lock();
}
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
@@ -550,15 +680,17 @@ void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
mAsyncResult = err;
if (err == OK) {
+ // update state before notifying client, so that if client calls back into NuPlayerDriver
+ // in response, NuPlayerDriver has the right state
+ mState = STATE_PREPARED;
if (mIsAsyncPrepare) {
- notifyListener(MEDIA_PREPARED);
+ notifyListener_l(MEDIA_PREPARED);
}
- mState = STATE_PREPARED;
} else {
+ mState = STATE_UNPREPARED;
if (mIsAsyncPrepare) {
- notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
}
- mState = STATE_UNPREPARED;
}
mCondition.broadcast();
@@ -570,4 +702,10 @@ void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
mPlayerFlags = flags;
}
+void NuPlayerDriver::setPauseStartedTimeIfNeeded() {
+ if (mPauseStartedTimeUs == -1) {
+ mPauseStartedTimeUs = ALooper::GetNowUs();
+ }
+}
+
} // namespace android