Merge change Iccfa50fe into eclair
* changes: Fix issue 2323920: Notification & A2DP audio stutter.
This commit is contained in:
commit
b1af3771c1
@ -932,6 +932,8 @@ status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended);
|
||||
result.append(buffer);
|
||||
write(fd, result.string(), result.size());
|
||||
|
||||
dumpBase(fd, args);
|
||||
@ -1344,7 +1346,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
|
||||
if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
|
||||
!track->isPaused())
|
||||
{
|
||||
//LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
|
||||
//LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this);
|
||||
|
||||
// compute volume for this track
|
||||
int16_t left, right;
|
||||
@ -1400,7 +1402,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
|
||||
track->mRetryCount = kMaxTrackRetries;
|
||||
mixerStatus = MIXER_TRACKS_READY;
|
||||
} else {
|
||||
//LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
|
||||
//LOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", track->name(), cblk->user, cblk->server, this);
|
||||
if (track->isStopped()) {
|
||||
track->reset();
|
||||
}
|
||||
@ -1914,7 +1916,7 @@ uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
|
||||
: MixerThread(audioFlinger, mainThread->getOutput(), id)
|
||||
: MixerThread(audioFlinger, mainThread->getOutput(), id), mWaitTimeMs(UINT_MAX)
|
||||
{
|
||||
mType = PlaybackThread::DUPLICATING;
|
||||
addOutputTrack(mainThread);
|
||||
@ -1952,6 +1954,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
|
||||
|
||||
if (checkForNewParameters_l()) {
|
||||
mixBufferSize = mFrameCount*mFrameSize;
|
||||
updateWaitTime();
|
||||
activeSleepTime = activeSleepTimeUs();
|
||||
idleSleepTime = idleSleepTimeUs();
|
||||
}
|
||||
@ -2003,7 +2006,11 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
|
||||
|
||||
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
|
||||
// mix buffers...
|
||||
mAudioMixer->process(curBuf);
|
||||
if (outputsReady(outputTracks)) {
|
||||
mAudioMixer->process(curBuf);
|
||||
} else {
|
||||
memset(curBuf, 0, mixBufferSize);
|
||||
}
|
||||
sleepTime = 0;
|
||||
writeFrames = mFrameCount;
|
||||
} else {
|
||||
@ -2054,6 +2061,7 @@ void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
|
||||
{
|
||||
int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
|
||||
OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
|
||||
this,
|
||||
mSampleRate,
|
||||
mFormat,
|
||||
mChannelCount,
|
||||
@ -2062,6 +2070,7 @@ void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
|
||||
thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
|
||||
mOutputTracks.add(outputTrack);
|
||||
LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
|
||||
updateWaitTime();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2072,12 +2081,50 @@ void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
|
||||
if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
|
||||
mOutputTracks[i]->destroy();
|
||||
mOutputTracks.removeAt(i);
|
||||
updateWaitTime();
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOGV("removeOutputTrack(): unkonwn thread: %p", thread);
|
||||
}
|
||||
|
||||
void AudioFlinger::DuplicatingThread::updateWaitTime()
|
||||
{
|
||||
mWaitTimeMs = UINT_MAX;
|
||||
for (size_t i = 0; i < mOutputTracks.size(); i++) {
|
||||
sp<ThreadBase> strong = mOutputTracks[i]->thread().promote();
|
||||
if (strong != NULL) {
|
||||
uint32_t waitTimeMs = (strong->frameCount() * 2 * 1000) / strong->sampleRate();
|
||||
if (waitTimeMs < mWaitTimeMs) {
|
||||
mWaitTimeMs = waitTimeMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AudioFlinger::DuplicatingThread::outputsReady(SortedVector< sp<OutputTrack> > &outputTracks)
|
||||
{
|
||||
for (size_t i = 0; i < outputTracks.size(); i++) {
|
||||
sp <ThreadBase> thread = outputTracks[i]->thread().promote();
|
||||
if (thread == 0) {
|
||||
LOGW("DuplicatingThread::outputsReady() could not promote thread on output track %p", outputTracks[i].get());
|
||||
return false;
|
||||
}
|
||||
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
|
||||
if (playbackThread->standby() && !playbackThread->isSuspended()) {
|
||||
LOGV("DuplicatingThread output track %p on thread %p Not Ready", outputTracks[i].get(), thread.get());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs()
|
||||
{
|
||||
return (mWaitTimeMs * 1000) / 2;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// TrackBase constructor must be called with AudioFlinger::mLock held
|
||||
@ -2616,12 +2663,13 @@ void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
|
||||
|
||||
AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
|
||||
const wp<ThreadBase>& thread,
|
||||
DuplicatingThread *sourceThread,
|
||||
uint32_t sampleRate,
|
||||
int format,
|
||||
int channelCount,
|
||||
int frameCount)
|
||||
: Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
|
||||
mActive(false)
|
||||
mActive(false), mSourceThread(sourceThread)
|
||||
{
|
||||
|
||||
PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
|
||||
@ -2630,10 +2678,9 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
|
||||
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
|
||||
mOutBuffer.frameCount = 0;
|
||||
mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
|
||||
playbackThread->mTracks.add(this);
|
||||
LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
|
||||
mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
|
||||
LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
|
||||
mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
|
||||
} else {
|
||||
LOGW("Error creating output track on thread %p", playbackThread);
|
||||
}
|
||||
@ -2673,7 +2720,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
|
||||
inBuffer.frameCount = frames;
|
||||
inBuffer.i16 = data;
|
||||
|
||||
uint32_t waitTimeLeftMs = mWaitTimeMs;
|
||||
uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
|
||||
|
||||
if (!mActive && frames != 0) {
|
||||
start();
|
||||
@ -2712,12 +2759,11 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
|
||||
mOutBuffer.frameCount = pInBuffer->frameCount;
|
||||
nsecs_t startTime = systemTime();
|
||||
if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
|
||||
LOGV ("OutputTrack::write() %p no more output buffers", this);
|
||||
LOGV ("OutputTrack::write() %p thread %p no more output buffers", this, mThread.unsafe_get());
|
||||
outputBufferFull = true;
|
||||
break;
|
||||
}
|
||||
uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime);
|
||||
LOGV("OutputTrack::write() to thread %p waitTimeMs %d waitTimeLeftMs %d", mThread.unsafe_get(), waitTimeMs, waitTimeLeftMs);
|
||||
if (waitTimeLeftMs >= waitTimeMs) {
|
||||
waitTimeLeftMs -= waitTimeMs;
|
||||
} else {
|
||||
@ -2738,7 +2784,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
|
||||
mBufferQueue.removeAt(0);
|
||||
delete [] pInBuffer->mBuffer;
|
||||
delete pInBuffer;
|
||||
LOGV("OutputTrack::write() %p released overflow buffer %d", this, mBufferQueue.size());
|
||||
LOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -2747,16 +2793,19 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
|
||||
|
||||
// If we could not write all frames, allocate a buffer and queue it for next time.
|
||||
if (inBuffer.frameCount) {
|
||||
if (mBufferQueue.size() < kMaxOverFlowBuffers) {
|
||||
pInBuffer = new Buffer;
|
||||
pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
|
||||
pInBuffer->frameCount = inBuffer.frameCount;
|
||||
pInBuffer->i16 = pInBuffer->mBuffer;
|
||||
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
|
||||
mBufferQueue.add(pInBuffer);
|
||||
LOGV("OutputTrack::write() %p adding overflow buffer %d", this, mBufferQueue.size());
|
||||
} else {
|
||||
LOGW("OutputTrack::write() %p no more overflow buffers", this);
|
||||
sp<ThreadBase> thread = mThread.promote();
|
||||
if (thread != 0 && !thread->standby()) {
|
||||
if (mBufferQueue.size() < kMaxOverFlowBuffers) {
|
||||
pInBuffer = new Buffer;
|
||||
pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
|
||||
pInBuffer->frameCount = inBuffer.frameCount;
|
||||
pInBuffer->i16 = pInBuffer->mBuffer;
|
||||
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
|
||||
mBufferQueue.add(pInBuffer);
|
||||
LOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size());
|
||||
} else {
|
||||
LOGW("OutputTrack::write() %p thread %p no more overflow buffers", mThread.unsafe_get(), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <media/IAudioFlinger.h>
|
||||
#include <media/IAudioFlingerClient.h>
|
||||
@ -208,6 +209,7 @@ private:
|
||||
class PlaybackThread;
|
||||
class MixerThread;
|
||||
class DirectOutputThread;
|
||||
class DuplicatingThread;
|
||||
class Track;
|
||||
class RecordTrack;
|
||||
|
||||
@ -324,6 +326,7 @@ private:
|
||||
void sendConfigEvent_l(int event, int param = 0);
|
||||
void processConfigEvents();
|
||||
int id() const { return mId;}
|
||||
bool standby() { return mStandby; }
|
||||
|
||||
mutable Mutex mLock;
|
||||
|
||||
@ -452,6 +455,7 @@ private:
|
||||
};
|
||||
|
||||
OutputTrack( const wp<ThreadBase>& thread,
|
||||
DuplicatingThread *sourceThread,
|
||||
uint32_t sampleRate,
|
||||
int format,
|
||||
int channelCount,
|
||||
@ -471,13 +475,12 @@ private:
|
||||
void clearBufferQueue();
|
||||
|
||||
// Maximum number of pending buffers allocated by OutputTrack::write()
|
||||
static const uint8_t kMaxOverFlowBuffers = 3;
|
||||
static const uint8_t kMaxOverFlowBuffers = 10;
|
||||
|
||||
Vector < Buffer* > mBufferQueue;
|
||||
AudioBufferProvider::Buffer mOutBuffer;
|
||||
uint32_t mWaitTimeMs;
|
||||
bool mActive;
|
||||
|
||||
DuplicatingThread* mSourceThread;
|
||||
}; // end of OutputTrack
|
||||
|
||||
PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
|
||||
@ -520,6 +523,7 @@ private:
|
||||
virtual int type() const { return mType; }
|
||||
void suspend() { mSuspended++; }
|
||||
void restore() { if (mSuspended) mSuspended--; }
|
||||
bool isSuspended() { return (mSuspended != 0); }
|
||||
virtual String8 getParameters(const String8& keys);
|
||||
virtual void audioConfigChanged(int event, int param = 0);
|
||||
|
||||
@ -635,9 +639,16 @@ private:
|
||||
virtual bool threadLoop();
|
||||
void addOutputTrack(MixerThread* thread);
|
||||
void removeOutputTrack(MixerThread* thread);
|
||||
uint32_t waitTimeMs() { return mWaitTimeMs; }
|
||||
protected:
|
||||
virtual uint32_t activeSleepTimeUs();
|
||||
|
||||
private:
|
||||
bool outputsReady(SortedVector< sp<OutputTrack> > &outputTracks);
|
||||
void updateWaitTime();
|
||||
|
||||
SortedVector < sp<OutputTrack> > mOutputTracks;
|
||||
uint32_t mWaitTimeMs;
|
||||
};
|
||||
|
||||
PlaybackThread *checkPlaybackThread_l(int output) const;
|
||||
|
Loading…
Reference in New Issue
Block a user