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