diff options
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp')
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 180 |
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 |