RTP: reduce the latency by overlapping AudioRecord and AudioTrack.

Change-Id: I00d750ee514ef68d5b2a28bd1893417ed70ef1fc
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 08a8d1c..bb45a9a 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -548,10 +548,11 @@
     }
     LOGD("reported frame count: output %d, input %d", output, input);
 
-    output = (output + sampleCount - 1) / sampleCount * sampleCount;
-    input = (input + sampleCount - 1) / sampleCount * sampleCount;
-    if (input < output * 2) {
-        input = output * 2;
+    if (output < sampleCount * 2) {
+        output = sampleCount * 2;
+    }
+    if (input < sampleCount * 2) {
+        input = sampleCount * 2;
     }
     LOGD("adjusted frame count: output %d, input %d", output, input);
 
@@ -587,7 +588,7 @@
     // Give device socket a reasonable timeout and buffer size.
     timeval tv;
     tv.tv_sec = 0;
-    tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
+    tv.tv_usec = 1000 * sampleCount / sampleRate * 1000;
     if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
         setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
         setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
@@ -764,38 +765,62 @@
     if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
         memset(output, 0, sizeof(output));
     }
-    if (mTrack.write(output, sizeof(output)) != (int)sizeof(output)) {
-        LOGE("cannot write to AudioTrack");
+
+    int16_t input[mSampleCount];
+    int toWrite = mSampleCount;
+    int toRead = (mMode == MUTED) ? 0 : mSampleCount;
+    int chances = 100;
+
+    while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
+        if (toWrite > 0) {
+            AudioTrack::Buffer buffer;
+            buffer.frameCount = toWrite;
+
+            status_t status = mTrack.obtainBuffer(&buffer, 1);
+            if (status == NO_ERROR) {
+                memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
+                toWrite -= buffer.frameCount;
+                mTrack.releaseBuffer(&buffer);
+            } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
+                LOGE("cannot write to AudioTrack");
+                return false;
+            }
+        }
+
+        if (toRead > 0) {
+            AudioRecord::Buffer buffer;
+            buffer.frameCount = mRecord.frameCount();
+
+            status_t status = mRecord.obtainBuffer(&buffer, 1);
+            if (status == NO_ERROR) {
+                int count = (buffer.frameCount < toRead) ?
+                        buffer.frameCount : toRead;
+                memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
+                toRead -= count;
+                if (buffer.frameCount < mRecord.frameCount()) {
+                    buffer.frameCount = count;
+                }
+                mRecord.releaseBuffer(&buffer);
+            } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
+                LOGE("cannot read from AudioRecord");
+                return false;
+            }
+        }
+    }
+
+    if (!chances) {
+        LOGE("device loop timeout");
         return false;
     }
 
     if (mMode != MUTED) {
-        uint32_t frameCount = mRecord.frameCount();
-        AudioRecord::Buffer input;
-        input.frameCount = frameCount;
-
-        if (mRecord.obtainBuffer(&input, -1) != NO_ERROR) {
-            LOGE("cannot read from AudioRecord");
-            return false;
-        }
-
-        if (input.frameCount < (uint32_t)mSampleCount) {
-            input.frameCount = 0;
+        if (mMode == NORMAL) {
+            send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
         } else {
-            if (mMode == NORMAL) {
-                send(mDeviceSocket, input.i8, sizeof(output), MSG_DONTWAIT);
-            } else {
-                // TODO: Echo canceller runs here.
-                send(mDeviceSocket, input.i8, sizeof(output), MSG_DONTWAIT);
-            }
-            if (input.frameCount < frameCount) {
-                input.frameCount = mSampleCount;
-            }
+            // TODO: Echo canceller runs here.
+            send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
         }
-
-        mRecord.releaseBuffer(&input);
     }
-
     return true;
 }