From f69a3f8dc54707e5be327e83cec742824d1ba263 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 22 Sep 2009 00:35:48 -0700 Subject: Fix issue 2116700: Ringer screwy while connected over Bluetooth. There was a regression introduced in AudioFlinger by change 24114 for suspended output: The suspended output was not reading and mixing audio tracks. When the phone is ringing, the A2DP output is suspended if the SCO headset and A2DP headset are the same. As the ringtone is played over the duplicated output, the fact that the A2DP output was not reading data was causing the hardware output to be stalled from time to time. --- libs/audioflinger/AudioFlinger.cpp | 203 +++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 97 deletions(-) (limited to 'libs/audioflinger') diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index e534447..6500791 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -1227,44 +1227,46 @@ bool AudioFlinger::MixerThread::threadLoop() enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); } - - // output audio to hardware - if (mSuspended) { - usleep(kMaxBufferRecoveryInUsecs); + if (LIKELY(enabledTracks)) { + // mix buffers... + mAudioMixer->process(curBuf); + sleepTime = 0; + standbyTime = systemTime() + kStandbyTimeInNsecs; } else { - if (LIKELY(enabledTracks)) { - // mix buffers... - mAudioMixer->process(curBuf); + sleepTime += kBufferRecoveryInUsecs; + if (sleepTime > kMaxBufferRecoveryInUsecs) { + sleepTime = kMaxBufferRecoveryInUsecs; + } + // There was nothing to mix this round, which means all + // active tracks were late. Sleep a little bit to give + // them another chance. If we're too late, write 0s to audio + // hardware to avoid underrun. + if (mBytesWritten != 0 && sleepTime >= kMaxBufferRecoveryInUsecs) { + memset (curBuf, 0, mixBufferSize); sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; - } else { - sleepTime += kBufferRecoveryInUsecs; - // There was nothing to mix this round, which means all - // active tracks were late. Sleep a little bit to give - // them another chance. If we're too late, write 0s to audio - // hardware to avoid underrun. - if (mBytesWritten == 0 || sleepTime < kMaxBufferRecoveryInUsecs) { - usleep(kBufferRecoveryInUsecs); - } else { - memset (curBuf, 0, mixBufferSize); - sleepTime = 0; - } } - // sleepTime == 0 means PCM data were written to mMixBuffer[] - if (sleepTime == 0) { - mLastWriteTime = systemTime(); - mInWrite = true; - int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); - if (bytesWritten > 0) mBytesWritten += bytesWritten; - mNumWrites++; - mInWrite = false; - mStandby = false; - nsecs_t delta = systemTime() - mLastWriteTime; - if (delta > maxPeriod) { - LOGW("write blocked for %llu msecs", ns2ms(delta)); - mNumDelayedWrites++; - } + } + + if (mSuspended) { + sleepTime = kMaxBufferRecoveryInUsecs; + } + // sleepTime == 0 means we must write to audio hardware + if (sleepTime == 0) { + mLastWriteTime = systemTime(); + mInWrite = true; + LOGV("mOutput->write() thread %p frames %d", this, mFrameCount); + int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); + if (bytesWritten > 0) mBytesWritten += bytesWritten; + mNumWrites++; + mInWrite = false; + mStandby = false; + nsecs_t delta = systemTime() - mLastWriteTime; + if (delta > maxPeriod) { + LOGW("write blocked for %llu msecs, thread %p", ns2ms(delta), this); + mNumDelayedWrites++; } + } else { + usleep(sleepTime); } // finally let go of all our tracks, without the lock held @@ -1718,50 +1720,55 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - // output audio to hardware - if (mSuspended) { - usleep(kMaxBufferRecoveryInUsecs); - } else { - if (activeTrack != 0) { - AudioBufferProvider::Buffer buffer; - size_t frameCount = mFrameCount; - curBuf = (int8_t *)mMixBuffer; - // output audio to hardware - while(frameCount) { - buffer.frameCount = frameCount; - activeTrack->getNextBuffer(&buffer); - if (UNLIKELY(buffer.raw == 0)) { - memset(curBuf, 0, frameCount * mFrameSize); - break; - } - memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize); - frameCount -= buffer.frameCount; - curBuf += buffer.frameCount * mFrameSize; - activeTrack->releaseBuffer(&buffer); + if (activeTrack != 0) { + AudioBufferProvider::Buffer buffer; + size_t frameCount = mFrameCount; + curBuf = (int8_t *)mMixBuffer; + // output audio to hardware + while(frameCount) { + buffer.frameCount = frameCount; + activeTrack->getNextBuffer(&buffer); + if (UNLIKELY(buffer.raw == 0)) { + memset(curBuf, 0, frameCount * mFrameSize); + break; } + memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize); + frameCount -= buffer.frameCount; + curBuf += buffer.frameCount * mFrameSize; + activeTrack->releaseBuffer(&buffer); + } + sleepTime = 0; + standbyTime = systemTime() + kStandbyTimeInNsecs; + } else { + sleepTime += kBufferRecoveryInUsecs; + if (sleepTime > kMaxBufferRecoveryInUsecs) { + sleepTime = kMaxBufferRecoveryInUsecs; + } + // There was nothing to mix this round, which means all + // active tracks were late. Sleep a little bit to give + // them another chance. If we're too late, write 0s to audio + // hardware to avoid underrun. + if (mBytesWritten != 0 && sleepTime >= kMaxBufferRecoveryInUsecs && + AudioSystem::isLinearPCM(mFormat)) { + memset (mMixBuffer, 0, mFrameCount * mFrameSize); sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; - } else { - sleepTime += kBufferRecoveryInUsecs; - if (mBytesWritten == 0 || !AudioSystem::isLinearPCM(mFormat) || - sleepTime < kMaxBufferRecoveryInUsecs) { - usleep(kBufferRecoveryInUsecs); - } else { - memset (mMixBuffer, 0, mFrameCount * mFrameSize); - sleepTime = 0; - } } + } - // sleepTime == 0 means PCM data were written to mMixBuffer[] - if (sleepTime == 0) { - mLastWriteTime = systemTime(); - mInWrite = true; - int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); - if (bytesWritten) mBytesWritten += bytesWritten; - mNumWrites++; - mInWrite = false; - mStandby = false; - } + if (mSuspended) { + sleepTime = kMaxBufferRecoveryInUsecs; + } + // sleepTime == 0 means we must write to audio hardware + if (sleepTime == 0) { + mLastWriteTime = systemTime(); + mInWrite = true; + int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); + if (bytesWritten) mBytesWritten += bytesWritten; + mNumWrites++; + mInWrite = false; + mStandby = false; + } else { + usleep(sleepTime); } // finally let go of removed track, without the lock held @@ -1913,38 +1920,40 @@ bool AudioFlinger::DuplicatingThread::threadLoop() } enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); - } + } - bool mustSleep = true; if (LIKELY(enabledTracks)) { // mix buffers... mAudioMixer->process(curBuf); - if (!mSuspended) { - for (size_t i = 0; i < outputTracks.size(); i++) { - outputTracks[i]->write(curBuf, mFrameCount); - mustSleep = false; - } - mStandby = false; - mBytesWritten += mixBufferSize; - } + sleepTime = 0; + standbyTime = systemTime() + kStandbyTimeInNsecs; } else { - // flush remaining overflow buffers in output tracks - for (size_t i = 0; i < outputTracks.size(); i++) { - if (outputTracks[i]->isActive()) { - outputTracks[i]->write(curBuf, 0); - standbyTime = systemTime() + kStandbyTimeInNsecs; - mustSleep = false; - } + sleepTime += kBufferRecoveryInUsecs; + if (sleepTime > kMaxBufferRecoveryInUsecs) { + sleepTime = kMaxBufferRecoveryInUsecs; + } + // There was nothing to mix this round, which means all + // active tracks were late. Sleep a little bit to give + // them another chance. If we're too late, write 0s to audio + // hardware to avoid underrun. + if (mBytesWritten != 0 && sleepTime >= kMaxBufferRecoveryInUsecs) { + memset (curBuf, 0, mixBufferSize); + sleepTime = 0; } } - if (mustSleep) { -// LOGV("threadLoop() sleeping %d", sleepTime); - usleep(sleepTime); - if (sleepTime < kMaxBufferRecoveryInUsecs) { - sleepTime += kBufferRecoveryInUsecs; + + if (mSuspended) { + sleepTime = kMaxBufferRecoveryInUsecs; + } + // sleepTime == 0 means we must write to audio hardware + if (sleepTime == 0) { + for (size_t i = 0; i < outputTracks.size(); i++) { + outputTracks[i]->write(curBuf, mFrameCount); } + mStandby = false; + mBytesWritten += mixBufferSize; } else { - sleepTime = kBufferRecoveryInUsecs; + usleep(sleepTime); } // finally let go of all our tracks, without the lock held -- cgit v1.1