diff options
author | Eric Laurent <elaurent@google.com> | 2010-12-17 10:27:02 -0800 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2010-12-17 10:27:02 -0800 |
commit | 626c85f3a9ec8e34a1e4af31eddf118d75ee6416 (patch) | |
tree | 6430f67b042ec913493476605a4a67d5cde5855c /services | |
parent | b5e8536e41bbbbfe336e1d9614c73278e51590eb (diff) | |
download | frameworks_av-626c85f3a9ec8e34a1e4af31eddf118d75ee6416.zip frameworks_av-626c85f3a9ec8e34a1e4af31eddf118d75ee6416.tar.gz frameworks_av-626c85f3a9ec8e34a1e4af31eddf118d75ee6416.tar.bz2 |
Fix issue 3217707.
The problem is that when the A2DP headset is disconnected, there is a transition
period during which the A2DP sink pumps data at a very high pace.
This makes that:
1 the audio flinger mixer thread spins and starves binder threads thus delaying
the completion of the A2DP output stream shutdown
2 we read the audio http audio stream faster than normal and we reach the end of stream
for audio while video is still playing if the streamed file is small enough.
The fix consists in detecting abnormal short write intervals and sleep to restore
a normal write pace.
Change-Id: Iab127882494ab0e26266371dc0ce5c2ff6fa476e
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/A2dpAudioInterface.cpp | 13 | ||||
-rw-r--r-- | services/audioflinger/A2dpAudioInterface.h | 2 |
2 files changed, 14 insertions, 1 deletions
diff --git a/services/audioflinger/A2dpAudioInterface.cpp b/services/audioflinger/A2dpAudioInterface.cpp index aee01ab..d926cb1 100644 --- a/services/audioflinger/A2dpAudioInterface.cpp +++ b/services/audioflinger/A2dpAudioInterface.cpp @@ -260,6 +260,7 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::set( if (pRate) *pRate = lRate; mDevice = device; + mBufferDurationUs = ((bufferSize() * 1000 )/ frameSize() / sampleRate()) * 1000; return NO_ERROR; } @@ -288,6 +289,7 @@ ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t if (mStandby) { acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock); mStandby = false; + mLastWriteTime = systemTime(); } status = init(); @@ -308,6 +310,15 @@ ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t buffer = (char *)buffer + status; } + // if A2DP sink runs abnormally fast, sleep a little so that audioflinger mixer thread + // does no spin and starve other threads. + // NOTE: It is likely that the A2DP headset is being disconnected + nsecs_t now = systemTime(); + if ((uint32_t)ns2us(now - mLastWriteTime) < (mBufferDurationUs >> 2)) { + LOGV("A2DP sink runs too fast"); + usleep(mBufferDurationUs - (uint32_t)ns2us(now - mLastWriteTime)); + } + mLastWriteTime = now; return bytes; } @@ -316,7 +327,7 @@ Error: standby(); // Simulate audio output timing in case of error - usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000); + usleep(mBufferDurationUs); return status; } diff --git a/services/audioflinger/A2dpAudioInterface.h b/services/audioflinger/A2dpAudioInterface.h index cef1926..dbe2c6a 100644 --- a/services/audioflinger/A2dpAudioInterface.h +++ b/services/audioflinger/A2dpAudioInterface.h @@ -117,6 +117,8 @@ private: uint32_t mDevice; bool mClosing; bool mSuspended; + nsecs_t mLastWriteTime; + uint32_t mBufferDurationUs; }; friend class A2dpAudioStreamOut; |