diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 2024cc0c2..ecfe1e0ed 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -932,6 +932,8 @@ status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const VectorframesReady() && (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< wpmRetryCount = 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::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 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 > &outputTracks) +{ + for (size_t i = 0; i < outputTracks.size(); i++) { + sp 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& 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 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); + } } } diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 8c29da859..12c90ebd1 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -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& 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, 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 > &outputTracks); + void updateWaitTime(); + SortedVector < sp > mOutputTracks; + uint32_t mWaitTimeMs; }; PlaybackThread *checkPlaybackThread_l(int output) const;