summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/TunnelPlayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/TunnelPlayer.cpp')
-rw-r--r--media/libstagefright/TunnelPlayer.cpp200
1 files changed, 132 insertions, 68 deletions
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
index f9d0976..1d76780 100644
--- a/media/libstagefright/TunnelPlayer.cpp
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -90,7 +90,9 @@ mIsFirstBuffer(false),
mFirstBufferResult(OK),
mFirstBuffer(NULL),
mAudioSink(audioSink),
-mObserver(observer) {
+mObserver(observer),
+mThreadState(NCREATED),
+mStopSinkPending(false) {
ALOGD("TunnelPlayer::TunnelPlayer()");
mTunnelObjectsAlive++;
numChannels = 0;
@@ -272,6 +274,7 @@ void TunnelPlayer::setSource(const sp<MediaSource> &source) {
}
status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
+ Mutex::Autolock _l(mLock);
CHECK(!mStarted);
CHECK(mSource != NULL);
@@ -374,8 +377,7 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
mStarted = true;
mAudioSink->start();
ALOGV("Waking up extractor thread");
- pthread_cond_signal(&extractor_cv);
-
+ mExtractorCV.signal();
return OK;
}
@@ -430,7 +432,7 @@ status_t TunnelPlayer::seekTo(int64_t time_us) {
mReachedOutputEOS = false;
if(mPaused == false) {
ALOGV("Going to signal extractor thread since playback is already going on ");
- pthread_cond_signal(&extractor_cv);
+ mExtractorCV.signal();
ALOGV("Signalled extractor thread.");
}
}
@@ -438,19 +440,16 @@ status_t TunnelPlayer::seekTo(int64_t time_us) {
return OK;
}
void TunnelPlayer::pause(bool playPendingSamples) {
+ Mutex::Autolock autoLock(mLock);
CHECK(mStarted);
if (mPaused) {
return;
}
- Mutex::Autolock autoLock(mLock);
ALOGV("pause: playPendingSamples %d", playPendingSamples);
mPaused = true;
int64_t playedTime = 0;
- if(!mPauseEventPending) {
- ALOGV("Posting an event for Pause timeout");
- mQueue.postEventWithDelay(mPauseEvent, TUNNEL_PAUSE_TIMEOUT_USEC);
- mPauseEventPending = true;
- }
+ schedPauseTimeOut();
+
getPlayedTimeFromDSP_l(&playedTime);
mPauseTime = mSeekTimeUs + playedTime;
if (mAudioSink.get() != NULL) {
@@ -470,7 +469,7 @@ void TunnelPlayer::resume() {
mPauseEventPending = false;
mQueue.cancelEvent(mPauseEvent->eventID());
}
-
+ mStopSinkPending = false;
}
audio_format_t format;
@@ -492,7 +491,7 @@ void TunnelPlayer::resume() {
ALOGV("Audio sink open succeeded.");
mAudioSink->start();
ALOGV("Audio sink start succeeded.");
- pthread_cond_signal(&extractor_cv);
+ mExtractorCV.signal();
ALOGV("Audio signalling extractor thread.");
}
}
@@ -547,6 +546,7 @@ void TunnelPlayer::reset() {
//doesnt matter if the event is really present or not
mPauseEventPending = false;
mQueue.cancelEvent(mPauseEvent->eventID());
+ mStopSinkPending = false;
mReachedEOS = true;
@@ -610,7 +610,6 @@ void *TunnelPlayer::extractorThreadWrapper(void *me) {
void TunnelPlayer::extractorThreadEntry() {
- pthread_mutex_lock(&extractor_mutex);
uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;
pid_t tid = gettid();
@@ -618,15 +617,20 @@ void TunnelPlayer::extractorThreadEntry() {
ANDROID_PRIORITY_AUDIO);
prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);
- ALOGV("extractorThreadEntry wait for signal \n");
- if (!mStarted) {
- pthread_cond_wait(&extractor_cv, &extractor_mutex);
+ {
+ Mutex::Autolock _l(mLock);
+ mThreadState = INITIALIZED;
+ ALOGV("extractorThreadEntry wait for signal \n");
+ if (!mStarted) {
+ mExtractorCV.wait(mLock);
+ }
+ if (killExtractorThread) {
+ mThreadState = EXITING;
+ return;
+ }
}
+
ALOGV("extractorThreadEntry ready to work \n");
- pthread_mutex_unlock(&extractor_mutex);
- if (killExtractorThread) {
- return;
- }
if(mSource != NULL) {
sp<MetaData> format = mSource->getFormat();
const char *mime;
@@ -637,52 +641,69 @@ void TunnelPlayer::extractorThreadEntry() {
int bytesWritten = 0;
bool lSeeking = false;
bool lPaused = false;
+ mThreadState = RUNNING;
+
while (!killExtractorThread) {
+ {
+ Mutex::Autolock _l(mLock);
+ if (mPaused) {
+ if (mStopSinkPending) {
+ ALOGD("extractor thread to stop and close the audio sink");
+ stopAudioSink();
+ }
+ }
- if (mReachedEOS || mPaused || !mIsAudioRouted) {
- ALOGV("Going to sleep before write since "
- "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
- mReachedEOS, mPaused, mIsAudioRouted);
- pthread_mutex_lock(&extractor_mutex);
- pthread_cond_wait(&extractor_cv, &extractor_mutex);
- pthread_mutex_unlock(&extractor_mutex);
- ALOGV("Woke up from sleep before write since "
- "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
- mReachedEOS, mPaused, mIsAudioRouted);
- continue;
+ if (mReachedEOS || mPaused || !mIsAudioRouted) {
+ ALOGV("Going to sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
+ mThreadState = SLEEPING;
+ mExtractorCV.wait(mLock);
+ ALOGV("Woke up from sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
+ mThreadState = RUNNING;
+ continue;
+ }
}
- if (!mIsA2DPEnabled) {
- ALOGV("FillBuffer: MemBuffer size %d", BufferSizeToUse);
- ALOGV("Fillbuffer started");
- bytesWritten = fillBuffer(local_buf, BufferSizeToUse);
- ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
- if(!killExtractorThread) {
- mLock.lock();
- lPaused = mPaused;
- mLock.unlock();
-
- if(lPaused == true) {
+ ALOGV("FillBuffer: MemBuffer size %d", BufferSizeToUse);
+ ALOGV("Fillbuffer started");
+ bytesWritten = fillBuffer(local_buf, BufferSizeToUse);
+ ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+ if (!killExtractorThread) {
+ {
+ Mutex::Autolock _l(mLock);
+ if (mPaused) {
//write only if player is not in paused state. Sleep on lock
// resume is called
ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
- pthread_mutex_lock(&extractor_mutex);
- pthread_cond_wait(&extractor_cv, &extractor_mutex);
+ if (mStopSinkPending) {
+ ALOGD("w/ a buffer, extractor thread to stop and close"
+ " the extractor thread");
+ stopAudioSink();
+ }
+
+ mThreadState = SLEEPING;
+ mExtractorCV.wait(mLock);
ALOGV("Going to unlock n decodethreadwrite since sink "
"resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
mPaused, mIsAudioRouted, mReachedEOS);
- pthread_mutex_unlock(&extractor_mutex);
+ mThreadState = RUNNING;
}
- mLock.lock();
- lSeeking = mSeeking||mInternalSeeking;
- mLock.unlock();
+ }
+
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
- if(lSeeking == false && (killExtractorThread == false)){
+ if (lSeeking == false && (killExtractorThread == false)) {
//if we are seeking, ignore write, otherwise write
- ALOGV("Fillbuffer before seek flag %d", mSeeking);
+ ALOGV("Fillbuffer before seek flag %d", mSeeking);
int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
- ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
- if(lWrittenBytes > 0) {
+ ALOGV("Fillbuffer after write, written bytes %d and seek flag %d",
+ lWrittenBytes, mSeeking);
+ if (lWrittenBytes > 0) {
//send EOS only if write was successful, if is_buffer_available
// is flushed out (which returns 0 do not SEND EOS
ALOGV("Fillbuffer after write and seek flag %d", mSeeking);
@@ -690,7 +711,7 @@ void TunnelPlayer::extractorThreadEntry() {
lSeeking = mSeeking||mInternalSeeking;
mLock.unlock();
//ignore posting zero length buffer is seeking is set
- if(mReachedEOS && bytesWritten && !lSeeking && (killExtractorThread == false)) {
+ if (mReachedEOS && bytesWritten && !lSeeking) {
ALOGV("Fillbuffer after write sent EOS flag %d", lSeeking);
mAudioSink->write(local_buf, 0);
} else {
@@ -701,25 +722,21 @@ void TunnelPlayer::extractorThreadEntry() {
} else {
ALOGV("write exited because of flush %d", mSeeking);
}
- } else {
- ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
- }
+ } else {
+ ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
}
}
}
+ mThreadState = EXITING;
free(local_buf);
//TODO: Call fillbuffer with different size and write to mAudioSink()
}
void TunnelPlayer::createThreads() {
- //Initialize all the Mutexes and Condition Variables
- pthread_mutex_init(&extractor_mutex, NULL);
- pthread_cond_init (&extractor_cv, NULL);
-
- // Create 4 threads Effect, decoder, event and A2dp
+ // Create the extractor thread
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
@@ -851,6 +868,19 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
int64_t TunnelPlayer::getRealTimeUs() {
Mutex::Autolock autoLock(mLock);
+
+ /*
+ * If it so happens that the client (e.g. AwesomePlayer),
+ * queries for the current time before compressed
+ * data from the new position is given to the compressed
+ * driver, we need to return the seek position
+ */
+ if (mSeeking || mInternalSeeking) {
+ ALOGV("Seek yet to be processed, return seek time as current time %lld",
+ mSeekTimeUs);
+ return mSeekTimeUs;
+ }
+
getOffsetRealTime_l(&mPositionTimeRealUs);
//update media time too
mPositionTimeMediaUs = mPositionTimeRealUs;
@@ -906,7 +936,7 @@ void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
}
ALOGV("requestAndWaitForExtractorThreadExit +1");
- pthread_cond_signal(&extractor_cv);
+ mExtractorCV.signal();
ALOGV("requestAndWaitForExtractorThreadExit +2");
mLock.unlock();
pthread_join(extractorThread,NULL);
@@ -942,12 +972,13 @@ void TunnelPlayer::onPauseTimeOut() {
// 2.) Close routing Session
ALOGV("onPauseTimeOut +4");
mAudioSink->flush();
- ALOGV("onPauseTimeOut +5");
- mAudioSink->stop();
- ALOGV("onPauseTimeOut +6");
- mAudioSink->close();
- ALOGV("onPauseTimeOut +7");
- mIsAudioRouted = false;
+ mStopSinkPending = true;
+
+ if (mThreadState == SLEEPING) {
+ stopAudioSink();
+ } else {
+ ALOGD("Delay stop and destroy of audio sink to the extractor thread");
+ }
// 3.) Release Wake Lock
releaseWakeLock();
@@ -955,4 +986,37 @@ void TunnelPlayer::onPauseTimeOut() {
}
+/* mLock acquired by caller */
+status_t TunnelPlayer::schedPauseTimeOut() {
+ if (mPauseEventPending) {
+ return INVALID_OPERATION;
+ }
+
+ ALOGD("Posting an event for Pause timeout by %d", gettid());
+ mQueue.postEventWithDelay(mPauseEvent, TUNNEL_PAUSE_TIMEOUT_USEC);
+ mPauseEventPending = true;
+ return NO_ERROR;
+}
+
+/* mLock acquired by caller */
+status_t TunnelPlayer::stopAudioSink() {
+ /* This function is for a very special purpose, hence the assertion */
+ CHECK(mPaused);
+
+ if (!mStopSinkPending) {
+ return INVALID_OPERATION;
+ }
+ mStopSinkPending = false;
+
+ if (!mIsAudioRouted) {
+ return INVALID_OPERATION;
+ }
+ ALOGD("stop and close the audio sink");
+ mAudioSink->stop();
+ mAudioSink->close();
+ mIsAudioRouted = false;
+ return NO_ERROR;
+}
+
+
} //namespace android