summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaynes Mathew George <hgeorge@codeaurora.org>2013-02-01 18:49:00 -0800
committerSteve Kondik <shade@chemlab.org>2013-02-27 09:54:05 -0800
commit9be07ef6a1d4dc591a25b3364a6ca0ad6f524ab9 (patch)
treebedd8ff41e77f38a68a1db51e20b05351aa307ea
parent1bf291a765608ea51db743389e01e98d9a5a8bf8 (diff)
downloadframeworks_av-9be07ef6a1d4dc591a25b3364a6ca0ad6f524ab9.zip
frameworks_av-9be07ef6a1d4dc591a25b3364a6ca0ad6f524ab9.tar.gz
frameworks_av-9be07ef6a1d4dc591a25b3364a6ca0ad6f524ab9.tar.bz2
libstagefright: Squashed commit of LPA/tunnel updates from CAF
libstagefright: Exceptions in using Tunnel mode decode - Accumulate all known exceptions to a separate function Change-Id: I61bbc288c9a087559db210e76141b8c57e67fff0 CRs-Fixed: 432080 libstagefright : Stability fixes for Tunnel Player (part 2) - Synchronize b/w reset() and onPauseTimeout - Synchronize b/w seekTo() and onPauseTimeout Change-Id: Ia5cfc6b4dcc326ead440fba35d809d4f3f1b5a81 CRs-Fixed: 449122 Revert "Revert "libstagefright: Convert mono to stereo for LPA clips"" This reverts commit 0db8a19fb3216a8a83d5d6cbd5f1ccbf997a20d8. libstagefright: Port Tunnel mode fixes to LPA - Miscellaneous fixes for seek, pause/resume, EOS handling - Miscellaneous fixes for synchronization between the decoder thread, TimedEventQueue and the player thread. - This change is a port of a similar set of changes made for TunnelPlayer Change-Id: I82c2904f7aedfb9c4f03200419fcba8b038e3d54 libstagefright: Avoid use of extra bytes to signal seek processed - A few bytes were reserved in the buffer sent by Tunnel/LPA player to audio HAL to indicate a seek has been processed and there is no need to skip it. - We won't need this method anymore as this can be fixed instead by synchronizing seekTo() and the extractor/decoder threads. Change-Id: Ic02ae1699bb59e2f6b8d9fb599d0fa43fd3f19e3 libstagefright: LPAPlayer synchronization fixes - synchronize b/w seekTo() and onPauseTimeout() - synchronize b/w reset() and onPauseTimeout() Change-Id: I29a4ccf02e28fe7b7c00e35a679ff2b5271ffb6f libstagefright: TunnelPlayer performance tweaks Some tweaks when TunnelPlayer is used for audio/video playback - Keep the extractor thread at ANDROID_PRIORITY_NORMAL - sched_yield() after reading a frame to give the video thread(s) (CallbackDispatcher and/or TimedEventQueue) to be scheduled Change-Id: If0d86d629fd0e15aff917af8589472578cd28bf4 CRs-Fixed: 444041
-rwxr-xr-xinclude/media/stagefright/LPAPlayer.h5
-rw-r--r--media/libstagefright/AwesomePlayer.cpp53
-rw-r--r--media/libstagefright/LPAPlayerALSA.cpp267
-rw-r--r--media/libstagefright/TunnelPlayer.cpp59
-rw-r--r--media/libstagefright/include/AwesomePlayer.h3
5 files changed, 289 insertions, 98 deletions
diff --git a/include/media/stagefright/LPAPlayer.h b/include/media/stagefright/LPAPlayer.h
index b0e1d31..91f9b3a 100755
--- a/include/media/stagefright/LPAPlayer.h
+++ b/include/media/stagefright/LPAPlayer.h
@@ -93,6 +93,8 @@ private:
bool mA2DPEnabled;
int32_t mChannelMask;
int32_t numChannels;
+ int32_t mNumOutputChannels;
+ int32_t mNumInputChannels;
int32_t mSampleRate;
int64_t mLatencyUs;
size_t mFrameSize;
@@ -258,6 +260,9 @@ private:
MediaPlayerBase::AudioSink *audioSink,
void *buffer, size_t size, void *cookie);
size_t AudioCallback(void *cookie, void *data, size_t size);
+ int64_t getMediaTimeUs_l();
+
+ void convertMonoToStereo(int16_t *data, size_t size);
LPAPlayer(const LPAPlayer &);
LPAPlayer &operator=(const LPAPlayer &);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 6dc18f8..6c1f4c5 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1537,9 +1537,10 @@ status_t AwesomePlayer::initAudioDecoder() {
int32_t isADTS = 0;
meta->findInt32( kKeyChannelCount, &nchannels );
meta->findInt32(kKeyIsADTS, &isADTS);
- if(isADTS == 1){
+ if (isADTS == 1) {
ALOGV("Widevine content\n");
}
+
ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",
nchannels);
#endif
@@ -1555,7 +1556,7 @@ status_t AwesomePlayer::initAudioDecoder() {
//widevine will fallback to software decoder
if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) &&
- mTunnelAliveAP == 0 && (isADTS == 0) &&
+ (mTunnelAliveAP == 0) && (isADTS == 0) &&
mAudioSink->realtime() &&
inSupportedTunnelFormats(mime)) {
@@ -1576,10 +1577,7 @@ status_t AwesomePlayer::initAudioDecoder() {
else
ALOGD("Normal Audio Playback");
- if (isStreamingHTTP()) {
- ALOGV("Streaming, force disable tunnel mode playback");
- mIsTunnelAudio = false;
- }
+ checkTunnelExceptions();
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
(mIsTunnelAudio && (mTunnelAliveAP == 0))) {
@@ -2050,8 +2048,8 @@ void AwesomePlayer::onVideoEvent() {
if (latenessUs > 40000) {
// We're more than 40ms late.
- ALOGV("we're late by %lld us (%.2f secs)",
- latenessUs, latenessUs / 1E6);
+ ALOGE("we're late by %lld us nowUs %lld, timeUs %lld",
+ latenessUs, nowUs, timeUs);
if (!(mFlags & SLOW_DECODER_HACK)
|| mSinceLastDropped > FRAME_DROP_FREQ)
@@ -3056,6 +3054,45 @@ bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
ALOGW("Tunnel playback unsupported for %s", mime);
return false;
}
+
+void AwesomePlayer::checkTunnelExceptions()
+{
+ /* exception 1: No streaming */
+ if (isStreamingHTTP()) {
+ ALOGV("Streaming, force disable tunnel mode playback");
+ mIsTunnelAudio = false;
+ return;
+ }
+
+ /* below exceptions are only for av content */
+ if (mVideoTrack == NULL) return;
+
+ /* exception 2: No avi having video + mp3 */
+ if (mExtractor == NULL) return;
+
+ sp<MetaData> metaData = mExtractor->getMetaData();
+ const char * container;
+
+ /*only proceed for avi content.*/
+ if (!metaData->findCString(kKeyMIMEType, &container) ||
+ strcmp(container, MEDIA_MIMETYPE_CONTAINER_AVI)) {
+ return;
+ }
+
+ CHECK(mAudioTrack != NULL);
+
+ const char * mime;
+ metaData = mAudioTrack->getFormat();
+ /*disable for av content having mp3*/
+ if (metaData->findCString(kKeyMIMEType, &mime) &&
+ !strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ ALOGV("Clip has AVI extractor and mp3 content, disable tunnel mode");
+ mIsTunnelAudio = false;
+ return;
+ }
+
+ return;
+}
#endif
} // namespace android
diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp
index 38d6bac..56746d0 100644
--- a/media/libstagefright/LPAPlayerALSA.cpp
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
@@ -51,11 +51,14 @@
static const char mName[] = "LPAPlayer";
-#define MEM_BUFFER_SIZE 262144
+#define MEM_PADDING 64
+#define MEM_BUFFER_SIZE (256*1024)
#define MEM_BUFFER_COUNT 4
#define PCM_FORMAT 2
#define NUM_FDS 2
+#define LPA_BUFFER_TIME 1500000
+
namespace android {
int LPAPlayer::objectsAlive = 0;
@@ -87,7 +90,8 @@ mAudioSink(audioSink),
mObserver(observer) {
ALOGV("LPAPlayer::LPAPlayer() ctor");
objectsAlive++;
- numChannels =0;
+ mNumOutputChannels =0;
+ mNumInputChannels = 0;
mPaused = false;
mIsA2DPEnabled = false;
mAudioFlinger = NULL;
@@ -256,20 +260,24 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) {
success = format->findInt32(kKeySampleRate, &mSampleRate);
CHECK(success);
- success = format->findInt32(kKeyChannelCount, &numChannels);
+ success = format->findInt32(kKeyChannelCount, &mNumInputChannels);
CHECK(success);
+ // Always produce stereo output
+ mNumOutputChannels = 2;
+
if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
// log only when there's a risk of ambiguity of channel mask selection
- ALOGI_IF(numChannels > 2,
- "source format didn't specify channel mask, using (%d) channel order", numChannels);
+ ALOGI_IF(mNumInputChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels);
mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
}
audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
AUDIO_OUTPUT_FLAG_DIRECT);
- ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags);
+ ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate,
+ mNumOutputChannels, mChannelMask, flags);
err = mAudioSink->open(
- mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&LPAPlayer::AudioSinkCallback,
this,
@@ -301,16 +309,40 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) {
status_t LPAPlayer::seekTo(int64_t time_us) {
Mutex::Autolock autoLock(mLock);
ALOGV("seekTo: time_us %lld", time_us);
- if ( mReachedEOS ) {
- mReachedEOS = false;
- mReachedOutputEOS = false;
+
+ int64_t mediaTimeUs = getMediaTimeUs_l();
+
+ if (mediaTimeUs != 0) {
+ //check for return conditions only if seektime
+ // is set
+ int64_t diffUs = time_us - mediaTimeUs;
+
+ if (labs(diffUs) < LPA_BUFFER_TIME) {
+ ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
+ mObserver->postAudioSeekComplete();
+ return OK;
+ }
}
+
mSeeking = true;
mSeekTimeUs = time_us;
mPauseTime = mSeekTimeUs;
ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
- mAudioSink->flush();
- pthread_cond_signal(&decoder_cv);
+
+ if (mIsAudioRouted) {
+ mAudioSink->flush();
+ }
+
+ if (mReachedEOS) {
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ if(mPaused == false) {
+ ALOGV("Going to signal decoder thread since playback is already going on ");
+ pthread_cond_signal(&decoder_cv);
+ ALOGV("Signalled extractor thread.");
+ }
+ }
+ ALOGV("seek done.");
return OK;
}
@@ -322,41 +354,26 @@ void LPAPlayer::pause(bool playPendingSamples) {
ALOGV("pause: playPendingSamples %d", playPendingSamples);
mPaused = true;
A2DPState state;
- if (playPendingSamples) {
- if (!mIsA2DPEnabled) {
- if (!mPauseEventPending) {
- ALOGV("Posting an event for Pause timeout");
- mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
- mPauseEventPending = true;
- }
- mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
- }
- else {
- mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
- }
- if (mAudioSink.get() != NULL)
- mAudioSink->pause();
+ if (!mIsA2DPEnabled) {
+ if (!mPauseEventPending) {
+ ALOGV("Posting an event for Pause timeout");
+ mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+ mPauseEventPending = true;
+ }
+ mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
} else {
- if (!mIsA2DPEnabled) {
- if(!mPauseEventPending) {
- ALOGV("Posting an event for Pause timeout");
- mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
- mPauseEventPending = true;
- }
- mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
- } else {
- mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
- }
- if (mAudioSink.get() != NULL) {
- ALOGV("AudioSink pause");
- mAudioSink->pause();
- }
+ mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
+ }
+
+ if (mAudioSink.get() != NULL) {
+ ALOGV("AudioSink pause");
+ mAudioSink->pause();
}
}
void LPAPlayer::resume() {
ALOGV("resume: mPaused %d",mPaused);
- Mutex::Autolock autoLock(mResumeLock);
+ Mutex::Autolock autoLock(mLock);
if ( mPaused) {
CHECK(mStarted);
if (!mIsA2DPEnabled) {
@@ -372,7 +389,7 @@ void LPAPlayer::resume() {
audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
AUDIO_OUTPUT_FLAG_DIRECT);
status_t err = mAudioSink->open(
- mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&LPAPlayer::AudioSinkCallback,
this,
@@ -394,30 +411,42 @@ size_t LPAPlayer::AudioSinkCallback(
void *buffer, size_t size, void *cookie) {
if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
LPAPlayer *me = (LPAPlayer *)cookie;
- me->mReachedEOS = true;
- me->mReachedOutputEOS = true;
- ALOGV("postAudioEOS");
- me->mObserver->postAudioEOS(0);
+ if(me->mReachedEOS == true) {
+ //in the case of seek all these flags will be reset
+ me->mReachedOutputEOS = true;
+ ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+ me->mObserver->postAudioEOS(0);
+ }else {
+ ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+ }
}
return 1;
}
void LPAPlayer::reset() {
+ ALOGD("Reset");
+
+ Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+ //cancel any pending onpause timeout events
+ //doesnt matter if the event is really present or not
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
- ALOGV("Reset");
// Close the audiosink after all the threads exited to make sure
mReachedEOS = true;
// make sure Decoder thread has exited
- ALOGV("Closing all the threads");
+ ALOGD("Closing all the threads");
requestAndWaitForDecoderThreadExit();
requestAndWaitForA2DPNotificationThreadExit();
- ALOGV("Close the Sink");
+ ALOGD("Close the Sink");
if (mIsAudioRouted) {
mAudioSink->stop();
mAudioSink->close();
mAudioSink.clear();
+ mIsAudioRouted = false;
}
// Make sure to release any buffer we hold onto so that the
// source is able to stop().
@@ -490,25 +519,80 @@ void LPAPlayer::decoderThreadEntry() {
return;
}
void* local_buf = malloc(MEM_BUFFER_SIZE);
+ if(local_buf == (void*) NULL) {
+ killDecoderThread = true;
+ ALOGE("Malloc failed");
+ return;
+ }
+ int *lptr = ((int*)local_buf);
int bytesWritten = 0;
+
+ if (!local_buf) {
+ ALOGE("Failed to allocate temporary buffer for decoderThread");
+ return;
+ }
+
+ bool lSeeking = false;
+ bool lPaused = false;
+
while (!killDecoderThread) {
if (mReachedEOS || mPaused || !mIsAudioRouted) {
+ ALOGV("Going to sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
pthread_mutex_lock(&decoder_mutex);
pthread_cond_wait(&decoder_cv, &decoder_mutex);
pthread_mutex_unlock(&decoder_mutex);
+ ALOGV("Woke up from sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
continue;
}
if (!mIsA2DPEnabled) {
ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
ALOGV("Fillbuffer started");
- //TODO: Add memset
- bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
- ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+ if (mNumInputChannels == 1) {
+ bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2);
+ CHECK(bytesWritten <= MEM_BUFFER_SIZE/2);
+
+ convertMonoToStereo((int16_t*)local_buf, bytesWritten);
+ bytesWritten *= 2;
+ } else {
+ bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
+ CHECK(bytesWritten <= MEM_BUFFER_SIZE);
+ }
+ ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
if(!killDecoderThread) {
- mAudioSink->write(local_buf, bytesWritten);
+ mLock.lock();
+ lPaused = mPaused;
+ mLock.unlock();
+
+ if(lPaused == true) {
+ //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(&decoder_mutex);
+ pthread_cond_wait(&decoder_cv, &decoder_mutex);
+ ALOGV("Going to unlock n decodethreadwrite since sink "
+ "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+ mPaused, mIsAudioRouted, mReachedEOS);
+ pthread_mutex_unlock(&decoder_mutex);
+ }
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
+
+ if(lSeeking == false && (killDecoderThread == false)){
+ //if we are seeking, ignore write, otherwise write
+ ALOGV("Fillbuffer before seeling flag %d", mSeeking);
+ int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+ ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+ } else {
+ ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+ }
}
}
}
@@ -580,19 +664,27 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
return 0;
}
+ if ((data == (void*) NULL) || size > MEM_BUFFER_SIZE) {
+ ALOGE("fillBuffer given wrong buffer");
+ return 0;
+ }
+
bool postSeekComplete = false;
size_t size_done = 0;
size_t size_remaining = size;
+ ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+
while (size_remaining > 0) {
MediaSource::ReadOptions options;
{
Mutex::Autolock autoLock(mLock);
- if (mSeeking) {
+ if(mSeeking) {
mInternalSeeking = false;
}
+
if (mSeeking || mInternalSeeking) {
if (mIsFirstBuffer) {
if (mFirstBuffer != NULL) {
@@ -609,8 +701,9 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
mInputBuffer = NULL;
}
- size_remaining = size;
+ // This is to ignore the data already filled in the output buffer
size_done = 0;
+ size_remaining = size;
mSeeking = false;
if (mObserver && !mInternalSeeking) {
@@ -618,6 +711,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
postSeekComplete = true;
}
mInternalSeeking = false;
+ ALOGV("fillBuffer: Setting seek flag in fill buffer");
}
}
@@ -635,14 +729,16 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
}
CHECK((err == OK && mInputBuffer != NULL)
- || (err != OK && mInputBuffer == NULL));
-
- Mutex::Autolock autoLock(mLock);
-
- if (err != OK) {
- mReachedEOS = true;
- mFinalStatus = err;
- break;
+ || (err != OK && mInputBuffer == NULL));
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (err != OK) {
+ ALOGD("fill buffer - reached eos true");
+ mReachedEOS = true;
+ mFinalStatus = err;
+ break;
+ }
}
CHECK(mInputBuffer->meta_data()->findInt64(
@@ -662,7 +758,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
size_t copy = size_remaining;
if (copy > mInputBuffer->range_length()) {
copy = mInputBuffer->range_length();
- }
+ } //is size_remaining < range_length impossible?
memcpy((char *)data + size_done,
(const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
@@ -712,9 +808,7 @@ int64_t LPAPlayer::getTimeStamp(A2DPState state) {
return timestamp;
}
-int64_t LPAPlayer::getMediaTimeUs() {
- Mutex::Autolock autoLock(mLock);
- ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+int64_t LPAPlayer::getMediaTimeUs_l() {
if (mPaused) {
return mPauseTime;
} else {
@@ -723,16 +817,21 @@ int64_t LPAPlayer::getMediaTimeUs() {
}
}
-bool LPAPlayer::getMediaTimeMapping(
- int64_t *realtime_us, int64_t *mediatime_us) {
+int64_t LPAPlayer::getMediaTimeUs() {
Mutex::Autolock autoLock(mLock);
+ ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+ return getMediaTimeUs_l();
+}
- *realtime_us = mPositionTimeRealUs;
- *mediatime_us = mPositionTimeMediaUs;
-
- return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
+bool LPAPlayer::getMediaTimeMapping(
+ int64_t *realtime_us, int64_t *mediatime_us) {
+ ALOGE("getMediaTimeMapping is invalid for LPA Player");
+ *realtime_us = -1;
+ *mediatime_us = -1;
+ return false;
}
+//lock taken in reset()
void LPAPlayer::requestAndWaitForDecoderThreadExit() {
if (!decoderThreadAlive)
@@ -745,8 +844,10 @@ void LPAPlayer::requestAndWaitForDecoderThreadExit() {
mAudioSink->flush();
pthread_cond_signal(&decoder_cv);
+ mLock.unlock();
pthread_join(decoderThread,NULL);
- ALOGV("decoder thread killed");
+ mLock.lock();
+ ALOGD("decoder thread killed");
}
@@ -761,7 +862,7 @@ void LPAPlayer::requestAndWaitForA2DPNotificationThreadExit() {
void LPAPlayer::onPauseTimeOut() {
ALOGV("onPauseTimeOut");
- Mutex::Autolock autoLock(mResumeLock);
+ Mutex::Autolock autoLock(mLock);
if (!mPauseEventPending) {
return;
}
@@ -790,4 +891,18 @@ void LPAPlayer::onPauseTimeOut() {
}
+//dup each mono frame
+void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
+{
+ int i =0;
+ int16_t *start_pointer = data;
+ int monoFrameCount = (size) / (sizeof(int16_t));
+
+ for (i = monoFrameCount; i > 0 ; i--) {
+ int16_t temp_sample = *(start_pointer + i - 1);
+ *(start_pointer + (i*2) - 1) = temp_sample;
+ *(start_pointer + (i*2) - 2) = temp_sample;
+ }
+}
+
} //namespace android
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
index c5f8066..3b45db4 100644
--- a/media/libstagefright/TunnelPlayer.cpp
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -51,6 +51,13 @@
static const char mName[] = "TunnelPlayer";
#define MEM_METADATA_SIZE 64
#define MEM_PADDING 64
+/*
+ * We need to reserve some space in the
+ * ion buffer (used in HAL) to save the
+ * metadata. so read from the extractor
+ * a somewhat smaller number of bytes.
+ * ideally this number should be bufer_size - sizeof(struct output_metadata_t)
+ */
#define MEM_BUFFER_SIZE (240*1024 - MEM_METADATA_SIZE)
#define MEM_BUFFER_COUNT 4
#define TUNNEL_BUFFER_TIME 1500000
@@ -374,7 +381,9 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
status_t TunnelPlayer::seekTo(int64_t time_us) {
- ALOGV("seekTo: time_us %lld", time_us);
+ ALOGD("seekTo: time_us %lld", time_us);
+
+ Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
//This can happen if the client calls seek
//without ever calling getPosition
@@ -385,19 +394,26 @@ status_t TunnelPlayer::seekTo(int64_t time_us) {
if (mPositionTimeRealUs > 0) {
//check for return conditions only if seektime
// is set
+ bool postSeekComplete = false;
+
if (time_us > mPositionTimeRealUs){
- if((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){
+ if ((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){
ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
- mObserver->postAudioSeekComplete();
- return OK;
+ postSeekComplete = true;
}
} else {
- if((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){
+ if ((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){
ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
- mObserver->postAudioSeekComplete();
- return OK;
+ postSeekComplete = true;
}
}
+
+ if (postSeekComplete) {
+ mLock.unlock(); //unlock and post
+ mObserver->postAudioSeekComplete();
+ mLock.lock();
+ return OK;
+ }
}
mSeeking = true;
@@ -502,6 +518,13 @@ size_t TunnelPlayer::AudioSinkCallback(
void TunnelPlayer::reset() {
ALOGV("Reset");
+ Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+ //cancel any pending onpause timeout events
+ //doesnt matter if the event is really present or not
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
+
mReachedEOS = true;
// make sure Decoder thread has exited
@@ -568,7 +591,8 @@ void TunnelPlayer::extractorThreadEntry() {
uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;
pid_t tid = gettid();
- androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ androidSetThreadPriority(tid, mHasVideo ? ANDROID_PRIORITY_NORMAL :
+ ANDROID_PRIORITY_AUDIO);
prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);
ALOGV("extractorThreadEntry wait for signal \n");
@@ -585,7 +609,7 @@ void TunnelPlayer::extractorThreadEntry() {
const char *mime;
bool success = format->findCString(kKeyMIMEType, &mime);
}
- void* local_buf = malloc(BufferSizeToUse + MEM_PADDING);
+ void* local_buf = malloc(BufferSizeToUse);
int *lptr = ((int*)local_buf);
int bytesWritten = 0;
bool lSeeking = false;
@@ -632,8 +656,7 @@ void TunnelPlayer::extractorThreadEntry() {
if(lSeeking == false && (killExtractorThread == false)){
//if we are seeking, ignore write, otherwise write
- ALOGV("Fillbuffer before write %d and seek flag %d", mSeeking,
- lptr[MEM_BUFFER_SIZE/sizeof(int)]);
+ 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) {
@@ -660,6 +683,7 @@ void TunnelPlayer::extractorThreadEntry() {
}
}
}
+
}
free(local_buf);
@@ -696,11 +720,11 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
size_t size_done = 0;
size_t size_remaining = size;
- int *ldataptr = (int*) data;
//clear the flag since we dont know whether we are seeking or not, yet
- ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 0;
ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+ bool yield = !mIsFirstBuffer;
+
while (size_remaining > 0) {
MediaSource::ReadOptions options;
{
@@ -738,7 +762,6 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
mInternalSeeking = false;
ALOGV("fillBuffer: Setting seek flag in fill buffer");
//set the flag since we know that this buffer is the new positions buffer
- ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 1;
}
}
if (mInputBuffer == NULL) {
@@ -787,6 +810,10 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
size_done += copy;
size_remaining -= copy;
+
+ if (mHasVideo && yield) {
+ sched_yield();
+ }
}
if(mReachedEOS)
memset((char *)data + size_done, 0x0, size_remaining);
@@ -841,7 +868,9 @@ bool TunnelPlayer::getMediaTimeMapping(
return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
}
+//lock has been taken in reset() to sync with onpausetimeout
void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
+ ALOGV("requestAndWaitForExtractorThreadExit -1");
if (!extractorThreadAlive)
return;
@@ -856,7 +885,9 @@ void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
ALOGV("requestAndWaitForExtractorThreadExit +1");
pthread_cond_signal(&extractor_cv);
ALOGV("requestAndWaitForExtractorThreadExit +2");
+ mLock.unlock();
pthread_join(extractorThread,NULL);
+ mLock.lock();
ALOGV("requestAndWaitForExtractorThreadExit +3");
ALOGV("Extractor thread killed");
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index ee885a5..8bda7f8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -309,6 +309,9 @@ private:
void logLate(int64_t ts, int64_t clock, int64_t delta);
void logOnTime(int64_t ts, int64_t clock, int64_t delta);
int64_t getTimeOfDayUs();
+#ifdef QCOM_HARDWARE
+ void checkTunnelExceptions();
+#endif
bool mStatistics;
struct TrackStat {