NBAIO: re-implement NBAIO Pipe and MonoPipe using fifo

Also removed const from NBAIO_Sink::availableToWrite() because
at least one implementation can no longer implement the const-ness.

Test: normal mixer, tee sink, and remote submix still work
Change-Id: I8461177efdf53bba8295b147e97835b018804903
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 8d1cb0f..3c5df1a 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -19,7 +19,6 @@
 #define LOG_TAG "MonoPipe"
 //#define LOG_NDEBUG 0
 
-#include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -32,11 +31,11 @@
 
 MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
         NBAIO_Sink(format),
-        mReqFrames(reqFrames),
+        // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
         mMaxFrames(roundup(reqFrames)),
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
-        mFront(0),
-        mRear(0),
+        mFifo(mMaxFrames, Format_frameSize(format), mBuffer, true /*throttlesWriter*/),
+        mFifoWriter(mFifo),
         mWriteTsValid(false),
         // mWriteTs
         mSetpoint((reqFrames * 11) / 16),
@@ -53,14 +52,14 @@
     free(mBuffer);
 }
 
-ssize_t MonoPipe::availableToWrite() const
+ssize_t MonoPipe::availableToWrite()
 {
     if (CC_UNLIKELY(!mNegotiated)) {
         return NEGOTIATE;
     }
-    // uses mMaxFrames not mReqFrames, so allows "over-filling" the pipe beyond requested limit
-    ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
-    ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
+    // uses mMaxFrames not reqFrames, so allows "over-filling" the pipe beyond requested limit
+    ssize_t ret = mFifoWriter.available();
+    ALOG_ASSERT(ret <= mMaxFrames);
     return ret;
 }
 
@@ -71,38 +70,33 @@
     }
     size_t totalFramesWritten = 0;
     while (count > 0) {
-        // can't return a negative value, as we already checked for !mNegotiated
-        size_t avail = availableToWrite();
-        size_t written = avail;
-        if (CC_LIKELY(written > count)) {
-            written = count;
-        }
-        size_t rear = mRear & (mMaxFrames - 1);
-        size_t part1 = mMaxFrames - rear;
-        if (part1 > written) {
-            part1 = written;
-        }
-        if (CC_LIKELY(part1 > 0)) {
-            memcpy((char *) mBuffer + (rear * mFrameSize), buffer, part1 * mFrameSize);
-            if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
-                size_t part2 = written - part1;
-                if (CC_LIKELY(part2 > 0)) {
-                    memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize);
-                }
+        ssize_t actual = mFifoWriter.write(buffer, count);
+        ALOG_ASSERT(actual <= count);
+        if (actual < 0) {
+            if (totalFramesWritten == 0) {
+                return actual;
             }
-            android_atomic_release_store(written + mRear, &mRear);
-            totalFramesWritten += written;
+            break;
         }
+        size_t written = (size_t) actual;
+        totalFramesWritten += written;
         if (!mWriteCanBlock || mIsShutdown) {
             break;
         }
         count -= written;
         buffer = (char *) buffer + (written * mFrameSize);
+        // TODO Replace this whole section by audio_util_fifo's setpoint feature.
         // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
         // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
         uint32_t ns;
         if (written > 0) {
-            size_t filled = (mMaxFrames - avail) + written;
+            ssize_t avail = mFifoWriter.available();
+            ALOG_ASSERT(avail <= mMaxFrames);
+            if (avail < 0) {
+                // don't return avail as status, because totalFramesWritten > 0
+                break;
+            }
+            size_t filled = mMaxFrames - (size_t) avail;
             // FIXME cache these values to avoid re-computation
             if (filled <= mSetpoint / 2) {
                 // pipe is (nearly) empty, fill quickly