summaryrefslogtreecommitdiffstats
path: root/media/libmedia/AudioTrackShared.cpp
diff options
context:
space:
mode:
authorAndy Hung <hunga@google.com>2015-07-15 17:04:20 -0700
committerAndy Hung <hunga@google.com>2015-07-16 10:27:06 -0700
commita2d75cdb1e389f2b4ce5992fb6652399b4d30966 (patch)
tree7356aa2f55de2f8c85c37f8a58fb4e135bb72754 /media/libmedia/AudioTrackShared.cpp
parent14ae2c0d1aa6e32e97cbb62dabb604820e1e5152 (diff)
downloadframeworks_av-a2d75cdb1e389f2b4ce5992fb6652399b4d30966.zip
frameworks_av-a2d75cdb1e389f2b4ce5992fb6652399b4d30966.tar.gz
frameworks_av-a2d75cdb1e389f2b4ce5992fb6652399b4d30966.tar.bz2
Fix AudioTrack flush pointer wrap
Occurs when read offset / write offset span the power of 2 mask boundary. Bug: 22513776 Change-Id: If863577dac6666e8b2083d78f78fe9b9490fcf76
Diffstat (limited to 'media/libmedia/AudioTrackShared.cpp')
-rw-r--r--media/libmedia/AudioTrackShared.cpp14
1 files changed, 13 insertions, 1 deletions
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 1d7aed2..c736ec6 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -374,6 +374,9 @@ void AudioTrackClientProxy::flush()
size_t increment = mFrameCountP2 << 1;
size_t mask = increment - 1;
audio_track_cblk_t* cblk = mCblk;
+ // mFlush is 32 bits concatenated as [ flush_counter ] [ newfront_offset ]
+ // Should newFlush = cblk->u.mStreaming.mRear? Only problem is
+ // if you want to flush twice to the same rear location after a 32 bit wrap.
int32_t newFlush = (cblk->u.mStreaming.mRear & mask) |
((cblk->u.mStreaming.mFlush & ~mask) + increment);
android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush);
@@ -613,9 +616,18 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
front = cblk->u.mStreaming.mFront;
if (flush != mFlush) {
// effectively obtain then release whatever is in the buffer
- size_t mask = (mFrameCountP2 << 1) - 1;
+ const size_t overflowBit = mFrameCountP2 << 1;
+ const size_t mask = overflowBit - 1;
int32_t newFront = (front & ~mask) | (flush & mask);
ssize_t filled = rear - newFront;
+ if (filled >= (ssize_t)overflowBit) {
+ // front and rear offsets span the overflow bit of the p2 mask
+ // so rebasing newFront on the front offset is off by the overflow bit.
+ // adjust newFront to match rear offset.
+ ALOGV("flush wrap: filled %#x >= overflowBit %#x", filled, overflowBit);
+ newFront += overflowBit;
+ filled -= overflowBit;
+ }
// Rather than shutting down on a corrupt flush, just treat it as a full flush
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "