Oboe FIFO: general purpose FIFO

Bug: 33347409
Test: test_oboe_api
Change-Id: I764fe372f00b98364e4d36e7841cb00fc8af5695
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/liboboe/src/fifo/FifoBuffer.cpp b/media/liboboe/src/fifo/FifoBuffer.cpp
new file mode 100644
index 0000000..c5489f1
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoBuffer.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstring>
+#include <unistd.h>
+
+#define LOG_TAG "FifoBuffer"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "FifoControllerBase.h"
+#include "FifoController.h"
+#include "FifoControllerIndirect.h"
+#include "FifoBuffer.h"
+
+FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
+        : mFrameCapacity(capacityInFrames)
+        , mBytesPerFrame(bytesPerFrame)
+        , mStorage(nullptr)
+        , mFramesReadCount(0)
+        , mFramesUnderrunCount(0)
+        , mUnderrunCount(0)
+{
+    // TODO Handle possible failures to allocate. Move out of constructor?
+    mFifo = new FifoController(capacityInFrames, capacityInFrames);
+    // allocate buffer
+    int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
+    mStorage = new uint8_t[bytesPerBuffer];
+    mStorageOwned = true;
+    ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
+          capacityInFrames, bytesPerFrame);
+}
+
+FifoBuffer::FifoBuffer( int32_t   bytesPerFrame,
+                        fifo_frames_t   capacityInFrames,
+                        fifo_counter_t *  readIndexAddress,
+                        fifo_counter_t *  writeIndexAddress,
+                        void *  dataStorageAddress
+                        )
+        : mFrameCapacity(capacityInFrames)
+        , mBytesPerFrame(bytesPerFrame)
+        , mStorage(static_cast<uint8_t *>(dataStorageAddress))
+        , mFramesReadCount(0)
+        , mFramesUnderrunCount(0)
+        , mUnderrunCount(0)
+{
+    // TODO Handle possible failures to allocate. Move out of constructor?
+    mFifo = new FifoControllerIndirect(capacityInFrames,
+                                       capacityInFrames,
+                                       readIndexAddress,
+                                       writeIndexAddress);
+    mStorageOwned = false;
+    ALOGD("FifoProcessor: capacityInFrames = %d, bytesPerFrame = %d",
+          capacityInFrames, bytesPerFrame);
+}
+
+FifoBuffer::~FifoBuffer() {
+    if (mStorageOwned) {
+        delete[] mStorage;
+    }
+    delete mFifo;
+}
+
+
+int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
+    return frames * mBytesPerFrame;
+}
+
+fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
+    size_t numBytes;
+    fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
+    fifo_frames_t framesToRead = numFrames;
+    // Is there enough data in the FIFO
+    if (framesToRead > framesAvailable) {
+        framesToRead = framesAvailable;
+    }
+    if (framesToRead == 0) {
+        return 0;
+    }
+
+    fifo_frames_t readIndex = mFifo->getReadIndex();
+    uint8_t *destination = (uint8_t *) buffer;
+    uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
+    if ((readIndex + framesToRead) > mFrameCapacity) {
+        // read in two parts, first part here
+        fifo_frames_t frames1 = mFrameCapacity - readIndex;
+        int32_t numBytes = convertFramesToBytes(frames1);
+        memcpy(destination, source, numBytes);
+        destination += numBytes;
+        // read second part
+        source = &mStorage[0];
+        fifo_frames_t frames2 = framesToRead - frames1;
+        numBytes = convertFramesToBytes(frames2);
+        memcpy(destination, source, numBytes);
+    } else {
+        // just read in one shot
+        numBytes = convertFramesToBytes(framesToRead);
+        memcpy(destination, source, numBytes);
+    }
+    mFifo->advanceReadIndex(framesToRead);
+
+    return framesToRead;
+}
+
+fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t framesToWrite) {
+    fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
+//    ALOGD("FifoBuffer::write() framesToWrite = %d, framesAvailable = %d",
+//         framesToWrite, framesAvailable);
+    if (framesToWrite > framesAvailable) {
+        framesToWrite = framesAvailable;
+    }
+    if (framesToWrite <= 0) {
+        return 0;
+    }
+
+    size_t numBytes;
+    fifo_frames_t writeIndex = mFifo->getWriteIndex();
+    int byteIndex = convertFramesToBytes(writeIndex);
+    const uint8_t *source = (const uint8_t *) buffer;
+    uint8_t *destination = &mStorage[byteIndex];
+    if ((writeIndex + framesToWrite) > mFrameCapacity) {
+        // write in two parts, first part here
+        fifo_frames_t frames1 = mFrameCapacity - writeIndex;
+        numBytes = convertFramesToBytes(frames1);
+        memcpy(destination, source, numBytes);
+//        ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
+        // read second part
+        source += convertFramesToBytes(frames1);
+        destination = &mStorage[0];
+        fifo_frames_t framesLeft = framesToWrite - frames1;
+        numBytes = convertFramesToBytes(framesLeft);
+//        ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
+        memcpy(destination, source, numBytes);
+    } else {
+        // just write in one shot
+        numBytes = convertFramesToBytes(framesToWrite);
+//        ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
+        memcpy(destination, source, numBytes);
+    }
+    mFifo->advanceWriteIndex(framesToWrite);
+
+    return framesToWrite;
+}
+
+fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
+    mLastReadSize = numFrames;
+    fifo_frames_t framesLeft = numFrames;
+    fifo_frames_t framesRead = read(buffer, numFrames);
+    framesLeft -= framesRead;
+    mFramesReadCount += framesRead;
+    mFramesUnderrunCount += framesLeft;
+    // Zero out any samples we could not set.
+    if (framesLeft > 0) {
+        mUnderrunCount++;
+        int32_t bytesToZero = convertFramesToBytes(framesLeft);
+        memset(buffer, 0, bytesToZero);
+    }
+
+    return framesRead;
+}
+
+fifo_frames_t FifoBuffer::getThreshold() {
+    return mFifo->getThreshold();
+}
+
+void FifoBuffer::setThreshold(fifo_frames_t threshold) {
+    mFifo->setThreshold(threshold);
+}
+
+fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
+    return mFifo->getCapacity();
+}
+