Add internal fifo API for obtain/release

Change-Id: Ife65218788d709768f0ede1cac144327a82e5f15
diff --git a/audio_utils/fifo.cpp b/audio_utils/fifo.cpp
index 2d70b95..76e19cf 100644
--- a/audio_utils/fifo.cpp
+++ b/audio_utils/fifo.cpp
@@ -27,7 +27,8 @@
 audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer) :
     mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
     mFudgeFactor(mFrameCountP2 - mFrameCount), mFrameSize(frameSize), mBuffer(buffer),
-    mLocalFront(0), mLocalRear(0), mSharedFront(0), mSharedRear(0)
+    mLocalFront(0), mLocalRear(0), mSharedFront(0), mSharedRear(0),
+    mReadObtained(0), mWriteObtained(0)
 {
     // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
     // be able to distinguish successful and error return values from read and write.
@@ -86,10 +87,27 @@
 ssize_t audio_utils_fifo::write(const void *buffer, size_t count)
         __attribute__((no_sanitize("integer")))
 {
+    audio_utils_iovec iovec[2];
+    ssize_t availToWrite = writeObtain(iovec, count);
+    if (availToWrite > 0) {
+        memcpy(iovec[0].mBase, buffer, iovec[0].mLen * mFrameSize);
+        if (iovec[1].mLen > 0) {
+            memcpy(iovec[1].mBase, (char *) buffer + (iovec[0].mLen * mFrameSize),
+                    iovec[1].mLen * mFrameSize);
+        }
+        writeRelease(availToWrite);
+    }
+    return availToWrite;
+}
+
+ssize_t audio_utils_fifo::writeObtain(audio_utils_iovec iovec[2], size_t count)
+        __attribute__((no_sanitize("integer")))
+{
     uint32_t front = (uint32_t) atomic_load_explicit(&mSharedFront, std::memory_order_acquire);
     uint32_t rear = mLocalRear;
     int32_t filled = diff(rear, front);
     if (filled < 0) {
+        mWriteObtained = 0;
         return (ssize_t) filled;
     }
     size_t availToWrite = (size_t) mFrameCount - (size_t) filled;
@@ -101,26 +119,50 @@
     if (part1 > availToWrite) {
         part1 = availToWrite;
     }
-    if (part1 > 0) {
-        memcpy((char *) mBuffer + (rearMasked * mFrameSize), buffer, part1 * mFrameSize);
-        size_t part2 = availToWrite - part1;
-        if (part2 > 0) {
-            memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize);
-        }
-        mLocalRear = sum(rear, availToWrite);
-        atomic_store_explicit(&mSharedRear, (uint_fast32_t) mLocalRear,
-                std::memory_order_release);
-    }
+    size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
+    iovec[0].mLen = part1;
+    iovec[0].mBase = part1 > 0 ? (char *) mBuffer + (rearMasked * mFrameSize) : NULL;
+    iovec[1].mLen = part2;
+    iovec[1].mBase = part2 > 0 ? mBuffer : NULL;
+    mWriteObtained = availToWrite;
     return availToWrite;
 }
 
+void audio_utils_fifo::writeRelease(size_t count)
+{
+    if (count > 0) {
+        ALOG_ASSERT(count <= mWriteObtained);
+        mLocalRear = sum(mLocalRear, count);
+        atomic_store_explicit(&mSharedRear, (uint_fast32_t) mLocalRear,
+                std::memory_order_release);
+        mWriteObtained -= count;
+    }
+}
+
 ssize_t audio_utils_fifo::read(void *buffer, size_t count)
         __attribute__((no_sanitize("integer")))
 {
+    audio_utils_iovec iovec[2];
+    ssize_t availToRead = readObtain(iovec, count);
+    if (availToRead > 0) {
+        memcpy(buffer, iovec[0].mBase, iovec[0].mLen * mFrameSize);
+        if (iovec[1].mLen > 0) {
+            memcpy((char *) buffer + (iovec[0].mLen * mFrameSize), iovec[1].mBase,
+                    iovec[1].mLen * mFrameSize);
+        }
+        readRelease(availToRead);
+    }
+    return availToRead;
+}
+
+ssize_t audio_utils_fifo::readObtain(audio_utils_iovec iovec[2], size_t count)
+        __attribute__((no_sanitize("integer")))
+{
     uint32_t rear = (uint32_t) atomic_load_explicit(&mSharedRear, std::memory_order_acquire);
     uint32_t front = mLocalFront;
     int32_t filled = diff(rear, front);
     if (filled < 0) {
+        mReadObtained = 0;
         return (ssize_t) filled;
     }
     size_t availToRead = (size_t) filled;
@@ -132,15 +174,22 @@
     if (part1 > availToRead) {
         part1 = availToRead;
     }
-    if (part1 > 0) {
-        memcpy(buffer, (char *) mBuffer + (frontMasked * mFrameSize), part1 * mFrameSize);
-        size_t part2 = availToRead - part1;
-        if (part2 > 0) {
-            memcpy((char *) buffer + (part1 * mFrameSize), mBuffer, part2 * mFrameSize);
-        }
-        mLocalFront = sum(front, availToRead);
+    size_t part2 = part1 > 0 ? availToRead - part1 : 0;
+    iovec[0].mLen = part1;
+    iovec[0].mBase = part1 > 0 ? (char *) mBuffer + (frontMasked * mFrameSize) : NULL;
+    iovec[1].mLen = part2;
+    iovec[1].mBase = part2 > 0 ? mBuffer : NULL;
+    mReadObtained = availToRead;
+    return availToRead;
+}
+
+void audio_utils_fifo::readRelease(size_t count)
+{
+    if (count > 0) {
+        ALOG_ASSERT(count <= mReadObtained);
+        mLocalFront = sum(mLocalFront, count);
         atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
                 std::memory_order_release);
+        mReadObtained -= count;
     }
-    return availToRead;
 }