Make AudioTrack/AudioRecord handle more than 2^32 frames

b/6160363
Change-Id: I471815012c6a113ec2c4dd7676e8fa288a70bc76
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 444665a..1fdc536 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -577,7 +577,7 @@
     uint32_t u = cblk->user;
     uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
 
-    if (u + framesReq > bufferEnd) {
+    if (framesReq > bufferEnd - u) {
         framesReq = bufferEnd - u;
     }
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index bafde3a..d73eabd 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -952,7 +952,7 @@
     uint32_t u = cblk->user;
     uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
 
-    if (u + framesReq > bufferEnd) {
+    if (framesReq > bufferEnd - u) {
         framesReq = bufferEnd - u;
     }
 
@@ -1382,8 +1382,9 @@
 
 uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
 {
-    uint32_t u = user;
+    ALOGV("stepuser %08x %08x %d", user, server, frameCount);
 
+    uint32_t u = user;
     u += frameCount;
     // Ensure that user is never ahead of server for AudioRecord
     if (flags & CBLK_DIRECTION_MSK) {
@@ -1392,12 +1393,19 @@
             bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
         }
     } else if (u > server) {
-        ALOGW("stepServer occurred after track reset");
+        ALOGW("stepUser occurred after track reset");
         u = server;
     }
 
-    if (u >= userBase + this->frameCount) {
-        userBase += this->frameCount;
+    uint32_t fc = this->frameCount;
+    if (u >= fc) {
+        // common case, user didn't just wrap
+        if (u - fc >= userBase ) {
+            userBase += fc;
+        }
+    } else if (u >= userBase + fc) {
+        // user just wrapped
+        userBase += fc;
     }
 
     user = u;
@@ -1412,12 +1420,15 @@
 
 bool audio_track_cblk_t::stepServer(uint32_t frameCount)
 {
+    ALOGV("stepserver %08x %08x %d", user, server, frameCount);
+
     if (!tryLock()) {
         ALOGW("stepServer() could not lock cblk");
         return false;
     }
 
     uint32_t s = server;
+    bool flushed = (s == user);
 
     s += frameCount;
     if (flags & CBLK_DIRECTION_MSK) {
@@ -1430,7 +1441,7 @@
         // while the mixer is processing a block: in this case,
         // stepServer() is called After the flush() has reset u & s and
         // we have s > u
-        if (s > user) {
+        if (flushed) {
             ALOGW("stepServer occurred after track reset");
             s = user;
         }
@@ -1444,8 +1455,16 @@
             loopStart = UINT_MAX;
         }
     }
-    if (s >= serverBase + this->frameCount) {
-        serverBase += this->frameCount;
+
+    uint32_t fc = this->frameCount;
+    if (s >= fc) {
+        // common case, server didn't just wrap
+        if (s - fc >= serverBase ) {
+            serverBase += fc;
+        }
+    } else if (s >= serverBase + fc) {
+        // server just wrapped
+        serverBase += fc;
     }
 
     server = s;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8662cb5..83af5f3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3409,6 +3409,11 @@
                 // clear all buffers
                 mCblk->frameCount = frameCount;
                 mCblk->sampleRate = sampleRate;
+// uncomment the following lines to quickly test 32-bit wraparound
+//                mCblk->user = 0xffff0000;
+//                mCblk->server = 0xffff0000;
+//                mCblk->userBase = 0xffff0000;
+//                mCblk->serverBase = 0xffff0000;
                 mChannelCount = channelCount;
                 mChannelMask = channelMask;
                 if (sharedBuffer == 0) {
@@ -3434,6 +3439,11 @@
         // clear all buffers
         mCblk->frameCount = frameCount;
         mCblk->sampleRate = sampleRate;
+// uncomment the following lines to quickly test 32-bit wraparound
+//        mCblk->user = 0xffff0000;
+//        mCblk->server = 0xffff0000;
+//        mCblk->userBase = 0xffff0000;
+//        mCblk->serverBase = 0xffff0000;
         mChannelCount = channelCount;
         mChannelMask = channelMask;
         mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
@@ -3513,7 +3523,7 @@
     if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
         ((unsigned long)bufferStart & (unsigned long)(frameSize - 1))) {
         ALOGE("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
-                server %d, serverBase %d, user %d, userBase %d",
+                server %u, serverBase %u, user %u, userBase %u",
                 bufferStart, bufferEnd, mBuffer, mBufferEnd,
                 cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
         return NULL;
@@ -3656,7 +3666,7 @@
         if (framesReq > framesReady) {
             framesReq = framesReady;
         }
-        if (s + framesReq > bufferEnd) {
+        if (framesReq > bufferEnd - s) {
             framesReq = bufferEnd - s;
         }
 
@@ -4323,7 +4333,7 @@
         if (framesReq > framesAvail) {
             framesReq = framesAvail;
         }
-        if (s + framesReq > bufferEnd) {
+        if (framesReq > bufferEnd - s) {
             framesReq = bufferEnd - s;
         }
 
@@ -4596,7 +4606,7 @@
     uint32_t u = cblk->user;
     uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
 
-    if (u + framesReq > bufferEnd) {
+    if (framesReq > bufferEnd - u) {
         framesReq = bufferEnd - u;
     }