summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaynes Mathew George <hgeorge@codeaurora.org>2013-02-21 20:06:04 -0800
committerSteve Kondik <shade@chemlab.org>2013-04-08 23:05:17 -0700
commit203e28ca88001f2a0f4db7a3018977c687333941 (patch)
treea73d73163f143d3a842bef7000f8bc7f909a98d8
parentba8b022736266d6dda1a1cd5986f8f999710db9f (diff)
downloadframeworks_av-203e28ca88001f2a0f4db7a3018977c687333941.zip
frameworks_av-203e28ca88001f2a0f4db7a3018977c687333941.tar.gz
frameworks_av-203e28ca88001f2a0f4db7a3018977c687333941.tar.bz2
libstagefright: Squashed audio fixes from CodeAurora
libstagefright: Return seek position until seek has been processed If it so happens that the client to TunnelPlayer (e.g. AwesomePlayer) queries for the current time before data from the new seek position is given to the compressed driver, we need to return the seek position Change-Id: If709e61f67cc8e81d34c14d19145dc61ecd82c2b CRs-Fixed: 454825 libstagefright: Use 64 bit offsets only when needed. For enabling >2GB recording, 64 bit offsets are needed for file writing. So, this feature was turned on by default. This in turn increased the file size. With this change, by default this feature will be off and turned on only when required. - Use 64 bit offsets for resolutions >= 720p. - Limit maximum file size for recording to 4GB. - Set max file size only if no value is set from the client. - Fix MPEG4Extractor to use 64 bit offsets CRs-Fixed: 273144, 285785, 288319 (cherry picked from commit 04476a3fb89dfbb025f7852dd4d62cae72385f1a) Change-Id: I00af2c7cddbbf86c566fe4bb989fe728ca06dd19 libstagefright: TunnelPlayer sync fix - Allow close on the AudioSink to be called from the extractor thread and the application thread. - This fixes a race condition where an onPauseTimeout event scheduled from the main thread closes the audio sink while the extractor thread was about to issue write() on audio HAL. (note: on HAL, not audio sink) Change-Id: I22a5c655dfcb40f3cbda3765dc23ad8e6f99c9bb CRs-Fixed: 443205 Frameworks/av: Fix to prevent deadlock in AudioEffects -Write is blocked waiting for effect chain lock and this causes decoder thread to wait indefintely. -Sometimes it is observed that effectschain is locked before mLPAEffectChain is initialized and but unlocking is skipped if mLPAEffectChain is initialized in between.Due to this LPA silence and framework reboot issues are observed as applyEffectsOn() cannot acquire lock to progress further. -Use flag to check if all effects have been locked and unlock accordingly to prevent the deadlock scenario. (cherry picked from commit 011db22abf565dfbe7f9d0a5c7af7564587b3b48) Change-Id: I82cfdab045ecf077f0ba0185fc693fc623fa10db CRs-Fixed: 435661, 435664, 435680, 430309 audio: Use tunnel player only for music stream - Check stream type before creating tunnel player to use tunnel player only for STREAM_MUSIC Change-Id: I6e4b58524e61441ad2e09499bd9187c6dd56cd3d framework/av: Fix for audio recording test through CTS - Issue: Failure in stop is observed with the audio recording test through CTS. TestScenario: When the audio record test is initiated in the CTS console, the recording session is force closed with a notification File Size limit exceeded. Further, the stop fails with the same message(notification of the File size exceeded error). - Cause: The calculation of nTotalBytesEstimate for the recording session exceeds the limit 95 percent of mMaxFileSizeLimitBytes. As a result of size deficit, the recording is stopped at the beginning of the recording session notifying MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED. - Fix: The factor size used in the calculation of nTotalBytesEstimate has been updated properly for 64bit file offset setting. The setParam64BitFileOffset in StagefrightRecorder::prepare() is executed based on two additional validations so that the factor size is updated appropriately. Change-Id: I4749ce8f9735ccc9e1d9e49718c36470837ab27f CRs-Fixed: 396057 audioflinger: apply volume on direct track when track is active During back to back tunnel playback, we encounter a race condition where setVolume can be called when the track is not updated to active state. Fix to apply the volume on direct track only when the track is in active state. Change-Id: I70c289fbf8a9266bae0bd01b04be9f43ad32c70d CRs-Fixed: 464148 LPAPlayer: Update condition to ignore seek - Reject seek if the new seek time is greater than the current position and within an empirical limit (default 60ms). - This limit must be measured for each target. Change-Id: I86b44679fb5fe442bb5adb510c62514f6be3d304 CRs-Fixed: 453067 audioflinger: for DirectAudioTrak, call startOutput before stream is active For LPA and Tunnel playback, when resume is done in paused state, before starting actual playback, volume should be set through AudioPolicy command thread. Change-Id: I7ee1098058c01a35a3e7181d3b291304abf3cac1 CRs-Fixed: 464348
-rw-r--r--include/media/MediaPlayerInterface.h6
-rwxr-xr-xinclude/media/stagefright/LPAPlayer.h4
-rw-r--r--include/media/stagefright/TunnelPlayer.h15
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp7
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h6
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp18
-rw-r--r--media/libstagefright/AwesomePlayer.cpp7
-rw-r--r--media/libstagefright/LPAPlayerALSA.cpp37
-rwxr-xr-xmedia/libstagefright/MPEG4Writer.cpp6
-rw-r--r--media/libstagefright/TunnelPlayer.cpp200
-rw-r--r--services/audioflinger/AudioFlinger.cpp27
11 files changed, 241 insertions, 92 deletions
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 00d53af..5f9eb01 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -1,5 +1,8 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,6 +90,9 @@ public:
virtual ssize_t channelCount() const = 0;
virtual ssize_t frameSize() const = 0;
virtual uint32_t latency() const = 0;
+#ifdef QCOM_HARDWARE
+ virtual audio_stream_type_t streamType() const {return AUDIO_STREAM_DEFAULT;}
+#endif
virtual float msecsPerFrame() const = 0;
virtual status_t getPosition(uint32_t *position) const = 0;
virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
diff --git a/include/media/stagefright/LPAPlayer.h b/include/media/stagefright/LPAPlayer.h
index 91f9b3a..ceba399 100755
--- a/include/media/stagefright/LPAPlayer.h
+++ b/include/media/stagefright/LPAPlayer.h
@@ -206,6 +206,9 @@ private:
void handleA2DPSwitch();
void onPauseTimeOut();
+ int64_t getMediaTimeUs_l();
+ bool seekTooClose(int64_t);
+
sp<AudioFlingerLPAdecodeClient> AudioFlingerClient;
friend class AudioFlingerLPAdecodeClient;
Mutex AudioFlingerLock;
@@ -260,7 +263,6 @@ 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);
diff --git a/include/media/stagefright/TunnelPlayer.h b/include/media/stagefright/TunnelPlayer.h
index 04cc750..0b083b3 100644
--- a/include/media/stagefright/TunnelPlayer.h
+++ b/include/media/stagefright/TunnelPlayer.h
@@ -133,8 +133,7 @@ private:
//Declare the condition Variables and Mutex
- pthread_mutex_t extractor_mutex;
- pthread_cond_t extractor_cv;
+ Condition mExtractorCV;
// make sure Decoder thread has exited
@@ -198,8 +197,18 @@ private:
sp<TimedEventQueue::Event> mPauseEvent;
bool mPauseEventPending;
+ typedef enum {
+ NCREATED = -1,
+ INITIALIZED,
+ RUNNING,
+ SLEEPING,
+ EXITING,
+ } ThreadState;
+
sp<MediaPlayerBase::AudioSink> mAudioSink;
AwesomePlayer *mObserver;
+ ThreadState mThreadState;
+ bool mStopSinkPending;
static size_t AudioSinkCallback(
MediaPlayerBase::AudioSink *audioSink,
@@ -218,6 +227,8 @@ private:
size_t fillBuffer(void *data, size_t size);
void reset();
+ status_t schedPauseTimeOut();
+ status_t stopAudioSink();
TunnelPlayer(const TunnelPlayer &);
TunnelPlayer &operator=(const TunnelPlayer &);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index f238e89..5b88f5f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1357,6 +1357,13 @@ uint32_t MediaPlayerService::AudioOutput::latency () const
return mTrack->latency();
}
+#ifdef QCOM_HARDWARE
+audio_stream_type_t MediaPlayerService::AudioOutput::streamType () const
+{
+ return mStreamType;
+}
+#endif
+
float MediaPlayerService::AudioOutput::msecsPerFrame() const
{
return mMsecsPerFrame;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 54df9d2..972de37 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -1,6 +1,9 @@
/*
**
** Copyright 2008, The Android Open Source Project
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution, Apache license notifications and license are retained
+** for attribution purposes only.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -85,6 +88,9 @@ class MediaPlayerService : public BnMediaPlayerService
virtual ssize_t channelCount() const;
virtual ssize_t frameSize() const;
virtual uint32_t latency() const;
+#ifdef QCOM_HARDWARE
+ virtual audio_stream_type_t streamType() const;
+#endif
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position) const;
virtual status_t getFramesWritten(uint32_t *frameswritten) const;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 94886e8..ad6d1cc 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -448,6 +448,11 @@ status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
ALOGW("Target file size (%lld bytes) is too small to be respected", bytes);
}
+ if (bytes >= 0xffffffffLL) {
+ ALOGW("Target file size (%lld bytes) too larger than supported, clip to 4GB", bytes);
+ bytes = 0xffffffffLL;
+ }
+
mMaxFileSizeBytes = bytes;
return OK;
}
@@ -765,7 +770,18 @@ status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listen
}
status_t StagefrightRecorder::prepare() {
- return OK;
+ ALOGV(" %s E", __func__ );
+
+ if(mVideoSource != VIDEO_SOURCE_LIST_END && mVideoEncoder != VIDEO_ENCODER_LIST_END && mVideoHeight && mVideoWidth && /*Video recording*/
+ (mMaxFileDurationUs <=0 || /*Max duration is not set*/
+ (mVideoHeight * mVideoWidth < 720 * 1280 && mMaxFileDurationUs > 30*60*1000*1000) ||
+ (mVideoHeight * mVideoWidth >= 720 * 1280 && mMaxFileDurationUs > 10*60*1000*1000))) {
+ /*Above Check can be further optimized for lower resolutions to reduce file size*/
+ ALOGV("File is huge so setting 64 bit file offsets");
+ setParam64BitFileOffset(true);
+ }
+ ALOGV(" %s X", __func__ );
+ return OK;
}
status_t StagefrightRecorder::start() {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 34e1007..c68b476 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -3064,6 +3064,13 @@ void AwesomePlayer::checkTunnelExceptions()
return;
}
+ /* exception 2: use tunnel player only for AUDIO_STREAM_MUSIC */
+ if (mAudioSink->streamType() != AUDIO_STREAM_MUSIC ) {
+ ALOGD("Use tunnel player only for AUDIO_STREAM_MUSIC");
+ mIsTunnelAudio = false;
+ return;
+ }
+
/* below exceptions are only for av content */
if (mVideoTrack == NULL) return;
diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp
index 56746d0..0aa419c 100644
--- a/media/libstagefright/LPAPlayerALSA.cpp
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -310,18 +310,11 @@ status_t LPAPlayer::seekTo(int64_t time_us) {
Mutex::Autolock autoLock(mLock);
ALOGV("seekTo: time_us %lld", time_us);
- 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;
- }
+ if (seekTooClose(time_us)) {
+ mLock.unlock();
+ mObserver->postAudioSeekComplete();
+ mLock.lock();
+ return OK;
}
mSeeking = true;
@@ -808,7 +801,9 @@ int64_t LPAPlayer::getTimeStamp(A2DPState state) {
return timestamp;
}
-int64_t LPAPlayer::getMediaTimeUs_l() {
+int64_t LPAPlayer::getMediaTimeUs_l( ) {
+ ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld",
+ mPaused, mSeekTimeUs, mPauseTime);
if (mPaused) {
return mPauseTime;
} else {
@@ -905,4 +900,20 @@ void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
}
}
+bool LPAPlayer::seekTooClose(int64_t time_us) {
+ int64_t t1 = getMediaTimeUs_l();
+ /*
+ * empirical
+ * -----------
+ * This constant signifies how much data (in Us) has been rendered by the
+ * DSP in the interval between the moment flush is issued on AudioSink to
+ * after ioctl(PAUSE) returns in Audio HAL. (flush triggers an implicit
+ * pause in audio HAL)
+ *
+ */
+ const int64_t kDeltaUs = 60000LL; /* 60-70ms on msm8974, must be measured for other targets */
+ t1 += kDeltaUs;
+ return (time_us > t1) && ((time_us - t1) <= LPA_BUFFER_TIME);
+}
+
} //namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 2b76660..6d1f8c6 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -44,6 +44,7 @@ namespace android {
static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
static const int64_t kMax32BitFileSize = 0x007fffffffLL;
+static const int64_t kMax64BitFileSize = 0x00ffffffffLL; //fat32 max size limited to 4GB
static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
static const uint8_t kNalUnitTypePicParamSet = 0x08;
static const int64_t kInitialDelayTimeUs = 700000LL;
@@ -525,11 +526,14 @@ status_t MPEG4Writer::start(MetaData *param) {
mIsFileSizeLimitExplicitlyRequested = true;
}
- int32_t use64BitOffset;
+ int32_t use64BitOffset = 0;
if (param &&
param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
use64BitOffset) {
mUse32BitOffset = false;
+ if (mMaxFileSizeLimitBytes == 0) {
+ mMaxFileSizeLimitBytes = kMax64BitFileSize;
+ }
}
if (mUse32BitOffset) {
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
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 88da88c..ed221ed 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -249,6 +249,9 @@ AudioFlinger::AudioFlinger()
mNextUniqueId(1),
mMode(AUDIO_MODE_INVALID),
mBtNrecIsOff(false)
+#ifdef QCOM_HARDWARE
+ ,mAllChainsLocked(false)
+#endif
{
}
@@ -6232,16 +6235,17 @@ AudioFlinger::DirectAudioTrack::~DirectAudioTrack() {
}
status_t AudioFlinger::DirectAudioTrack::start() {
+ AudioSystem::startOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType);
if(mIsPaused) {
mIsPaused = false;
mOutputDesc->stream->start(mOutputDesc->stream);
}
mOutputDesc->mActive = true;
- AudioSystem::startOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType);
return NO_ERROR;
}
void AudioFlinger::DirectAudioTrack::stop() {
+ ALOGV("DirectAudioTrack::stop");
mOutputDesc->mActive = false;
mOutputDesc->stream->stop(mOutputDesc->stream);
AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType);
@@ -6290,11 +6294,14 @@ void AudioFlinger::DirectAudioTrack::mute(bool muted) {
}
void AudioFlinger::DirectAudioTrack::setVolume(float left, float right) {
- mOutputDesc->mVolumeLeft = left;
- mOutputDesc->mVolumeRight = right;
- mOutputDesc->stream->set_volume(mOutputDesc->stream,
+ ALOGV("DirectAudioTrack::setVolume left: %f, right: %f", left, right);
+ if(mOutputDesc && mOutputDesc->mActive) {
+ mOutputDesc->mVolumeLeft = left;
+ mOutputDesc->mVolumeRight = right;
+ mOutputDesc->stream->set_volume(mOutputDesc->stream,
left * mOutputDesc->mVolumeScale,
right* mOutputDesc->mVolumeScale);
+ }
}
int64_t AudioFlinger::DirectAudioTrack::getTimeStamp() {
@@ -8760,11 +8767,19 @@ void AudioFlinger::ThreadBase::lockEffectChains_l(
Vector< sp<AudioFlinger::EffectChain> >& effectChains)
{
effectChains = mEffectChains;
+#ifdef QCOM_HARDWARE
+ mAudioFlinger->mAllChainsLocked = true;
+#endif
for (size_t i = 0; i < mEffectChains.size(); i++) {
#ifdef QCOM_HARDWARE
- if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain)
+ if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain) {
#endif
mEffectChains[i]->lock();
+#ifdef QCOM_HARDWARE
+ } else {
+ mAudioFlinger-> mAllChainsLocked = false;
+ }
+#endif
}
}
@@ -8773,7 +8788,7 @@ void AudioFlinger::ThreadBase::unlockEffectChains(
{
for (size_t i = 0; i < effectChains.size(); i++) {
#ifdef QCOM_HARDWARE
- if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain)
+ if (mAudioFlinger-> mAllChainsLocked || mEffectChains[i] != mAudioFlinger->mLPAEffectChain)
#endif
effectChains[i]->unlock();
}