Reduce audio output latency

This patch reduces latency in the OpenSL ES player path by calling the
callback immediately before data is consumed, rather than after.

Bug: 12246268
Change-Id: I8273b4a03f16011beec21dd52545f8ad1a25fd95
diff --git a/src/android/AudioPlayer_to_android.cpp b/src/android/AudioPlayer_to_android.cpp
index 696e60d..6e73396 100644
--- a/src/android/AudioPlayer_to_android.cpp
+++ b/src/android/AudioPlayer_to_android.cpp
@@ -1188,7 +1188,6 @@
 
     case android::AudioTrack::EVENT_MORE_DATA: {
         //SL_LOGV("received event EVENT_MORE_DATA from AudioTrack TID=%d", gettid());
-        slBufferQueueCallback callback = NULL;
         slPrefetchCallback prefetchCallback = NULL;
         void *prefetchContext = NULL;
         SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
@@ -1197,6 +1196,18 @@
         // retrieve data from the buffer queue
         interface_lock_exclusive(&ap->mBufferQueue);
 
+        if (ap->mBufferQueue.mCallbackPending) {
+            // call callback with lock not held
+            slBufferQueueCallback callback = ap->mBufferQueue.mCallback;
+            if (NULL != callback) {
+                callbackPContext = ap->mBufferQueue.mContext;
+                interface_unlock_exclusive(&ap->mBufferQueue);
+                (*callback)(&ap->mBufferQueue.mItf, callbackPContext);
+                interface_lock_exclusive(&ap->mBufferQueue);
+                ap->mBufferQueue.mCallbackPending = false;
+            }
+        }
+
         if (ap->mBufferQueue.mState.count != 0) {
             //SL_LOGV("nbBuffers in queue = %u",ap->mBufferQueue.mState.count);
             assert(ap->mBufferQueue.mFront != ap->mBufferQueue.mRear);
@@ -1204,20 +1215,19 @@
             BufferHeader *oldFront = ap->mBufferQueue.mFront;
             BufferHeader *newFront = &oldFront[1];
 
-            // declared as void * because this code supports both 8-bit and 16-bit PCM data
+            size_t availSource = oldFront->mSize - ap->mBufferQueue.mSizeConsumed;
+            size_t availSink = pBuff->size;
+            size_t bytesToCopy = availSource < availSink ? availSource : availSink;
             void *pSrc = (char *)oldFront->mBuffer + ap->mBufferQueue.mSizeConsumed;
-            if (ap->mBufferQueue.mSizeConsumed + pBuff->size < oldFront->mSize) {
-                // can't consume the whole or rest of the buffer in one shot
-                ap->mBufferQueue.mSizeConsumed += pBuff->size;
-                // leave pBuff->size untouched
-                // consume data
-                // FIXME can we avoid holding the lock during the copy?
-                memcpy (pBuff->raw, pSrc, pBuff->size);
-            } else {
-                // finish consuming the buffer or consume the buffer in one shot
-                pBuff->size = oldFront->mSize - ap->mBufferQueue.mSizeConsumed;
-                ap->mBufferQueue.mSizeConsumed = 0;
+            memcpy(pBuff->raw, pSrc, bytesToCopy);
 
+            if (bytesToCopy < availSource) {
+                ap->mBufferQueue.mSizeConsumed += bytesToCopy;
+                // pBuff->size is already equal to bytesToCopy in this case
+            } else {
+                // consumed an entire buffer, dequeue
+                pBuff->size = bytesToCopy;
+                ap->mBufferQueue.mSizeConsumed = 0;
                 if (newFront ==
                         &ap->mBufferQueue.mArray
                             [ap->mBufferQueue.mNumBuffers + 1])
@@ -1228,16 +1238,7 @@
 
                 ap->mBufferQueue.mState.count--;
                 ap->mBufferQueue.mState.playIndex++;
-
-                // consume data
-                // FIXME can we avoid holding the lock during the copy?
-                memcpy (pBuff->raw, pSrc, pBuff->size);
-
-                // data has been consumed, and the buffer queue state has been updated
-                // we will notify the client if applicable
-                callback = ap->mBufferQueue.mCallback;
-                // save callback data
-                callbackPContext = ap->mBufferQueue.mContext;
+                ap->mBufferQueue.mCallbackPending = true;
             }
         } else { // empty queue
             // signal no data available
@@ -1277,9 +1278,6 @@
                         SL_PREFETCHEVENT_FILLLEVELCHANGE);
             }
         }
-        if (NULL != callback) {
-            (*callback)(&ap->mBufferQueue.mItf, callbackPContext);
-        }
     }
     break;
 
diff --git a/src/itf/IBufferQueue.c b/src/itf/IBufferQueue.c
index 9503694..4e310b7 100644
--- a/src/itf/IBufferQueue.c
+++ b/src/itf/IBufferQueue.c
@@ -96,6 +96,7 @@
             thiz->mState.count = 0;
             thiz->mState.playIndex = 0;
             thiz->mSizeConsumed = 0;
+            thiz->mCallbackPending = false;
         }
     }
 #endif
@@ -185,6 +186,7 @@
     thiz->mRear = NULL;
 #ifdef ANDROID
     thiz->mSizeConsumed = 0;
+    thiz->mCallbackPending = false;
 #endif
     BufferHeader *bufferHeader = thiz->mTypical;
     unsigned i;
diff --git a/src/itfstruct.h b/src/itfstruct.h
index 1712a87..537c12b 100644
--- a/src/itfstruct.h
+++ b/src/itfstruct.h
@@ -237,6 +237,7 @@
     BufferHeader *mFront, *mRear;
 #ifdef ANDROID
     SLuint32 mSizeConsumed;
+    bool mCallbackPending;
 #endif
     // saves a malloc in the typical case
 #define BUFFER_HEADER_TYPICAL 4