Home | History | Annotate | Download | only in fifo
      1 /*
      2  * Copyright 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cstring>
     18 #include <unistd.h>
     19 
     20 
     21 #define LOG_TAG "FifoBuffer"
     22 //#define LOG_NDEBUG 0
     23 #include <utils/Log.h>
     24 
     25 #include "FifoControllerBase.h"
     26 #include "FifoController.h"
     27 #include "FifoControllerIndirect.h"
     28 #include "FifoBuffer.h"
     29 
     30 using namespace android; // TODO just import names needed
     31 
     32 FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
     33         : mFrameCapacity(capacityInFrames)
     34         , mBytesPerFrame(bytesPerFrame)
     35         , mStorage(nullptr)
     36         , mFramesReadCount(0)
     37         , mFramesUnderrunCount(0)
     38         , mUnderrunCount(0)
     39 {
     40     // TODO Handle possible failures to allocate. Move out of constructor?
     41     mFifo = new FifoController(capacityInFrames, capacityInFrames);
     42     // allocate buffer
     43     int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
     44     mStorage = new uint8_t[bytesPerBuffer];
     45     mStorageOwned = true;
     46     ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
     47           capacityInFrames, bytesPerFrame);
     48 }
     49 
     50 FifoBuffer::FifoBuffer( int32_t   bytesPerFrame,
     51                         fifo_frames_t   capacityInFrames,
     52                         fifo_counter_t *  readIndexAddress,
     53                         fifo_counter_t *  writeIndexAddress,
     54                         void *  dataStorageAddress
     55                         )
     56         : mFrameCapacity(capacityInFrames)
     57         , mBytesPerFrame(bytesPerFrame)
     58         , mStorage(static_cast<uint8_t *>(dataStorageAddress))
     59         , mFramesReadCount(0)
     60         , mFramesUnderrunCount(0)
     61         , mUnderrunCount(0)
     62 {
     63     mFifo = new FifoControllerIndirect(capacityInFrames,
     64                                        capacityInFrames,
     65                                        readIndexAddress,
     66                                        writeIndexAddress);
     67     mStorageOwned = false;
     68 }
     69 
     70 FifoBuffer::~FifoBuffer() {
     71     if (mStorageOwned) {
     72         delete[] mStorage;
     73     }
     74     delete mFifo;
     75 }
     76 
     77 
     78 int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
     79     return frames * mBytesPerFrame;
     80 }
     81 
     82 void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
     83                                     int32_t framesAvailable,
     84                                     int32_t startIndex) {
     85     wrappingBuffer->data[1] = nullptr;
     86     wrappingBuffer->numFrames[1] = 0;
     87     if (framesAvailable > 0) {
     88 
     89         uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
     90         // Does the available data cross the end of the FIFO?
     91         if ((startIndex + framesAvailable) > mFrameCapacity) {
     92             wrappingBuffer->data[0] = source;
     93             wrappingBuffer->numFrames[0] = mFrameCapacity - startIndex;
     94             wrappingBuffer->data[1] = &mStorage[0];
     95             wrappingBuffer->numFrames[1] = mFrameCapacity - startIndex;
     96 
     97         } else {
     98             wrappingBuffer->data[0] = source;
     99             wrappingBuffer->numFrames[0] = framesAvailable;
    100         }
    101     } else {
    102         wrappingBuffer->data[0] = nullptr;
    103         wrappingBuffer->numFrames[0] = 0;
    104     }
    105 
    106 }
    107 
    108 fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
    109     fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
    110     fifo_frames_t startIndex = mFifo->getReadIndex();
    111     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
    112     return framesAvailable;
    113 }
    114 
    115 fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
    116     fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
    117     fifo_frames_t startIndex = mFifo->getWriteIndex();
    118     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
    119     return framesAvailable;
    120 }
    121 
    122 fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
    123     WrappingBuffer wrappingBuffer;
    124     uint8_t *destination = (uint8_t *) buffer;
    125     fifo_frames_t framesLeft = numFrames;
    126 
    127     getFullDataAvailable(&wrappingBuffer);
    128 
    129     // Read data in one or two parts.
    130     int partIndex = 0;
    131     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
    132         fifo_frames_t framesToRead = framesLeft;
    133         fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
    134         if (framesAvailable > 0) {
    135             if (framesToRead > framesAvailable) {
    136                 framesToRead = framesAvailable;
    137             }
    138             int32_t numBytes = convertFramesToBytes(framesToRead);
    139             memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
    140 
    141             destination += numBytes;
    142             framesLeft -= framesToRead;
    143         } else {
    144             break;
    145         }
    146         partIndex++;
    147     }
    148     fifo_frames_t framesRead = numFrames - framesLeft;
    149     mFifo->advanceReadIndex(framesRead);
    150     return framesRead;
    151 }
    152 
    153 fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) {
    154     WrappingBuffer wrappingBuffer;
    155     uint8_t *source = (uint8_t *) buffer;
    156     fifo_frames_t framesLeft = numFrames;
    157 
    158     getEmptyRoomAvailable(&wrappingBuffer);
    159 
    160     // Read data in one or two parts.
    161     int partIndex = 0;
    162     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
    163         fifo_frames_t framesToWrite = framesLeft;
    164         fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
    165         if (framesAvailable > 0) {
    166             if (framesToWrite > framesAvailable) {
    167                 framesToWrite = framesAvailable;
    168             }
    169             int32_t numBytes = convertFramesToBytes(framesToWrite);
    170             memcpy(wrappingBuffer.data[partIndex], source, numBytes);
    171 
    172             source += numBytes;
    173             framesLeft -= framesToWrite;
    174         } else {
    175             break;
    176         }
    177         partIndex++;
    178     }
    179     fifo_frames_t framesWritten = numFrames - framesLeft;
    180     mFifo->advanceWriteIndex(framesWritten);
    181     return framesWritten;
    182 }
    183 
    184 fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
    185     mLastReadSize = numFrames;
    186     fifo_frames_t framesLeft = numFrames;
    187     fifo_frames_t framesRead = read(buffer, numFrames);
    188     framesLeft -= framesRead;
    189     mFramesReadCount += framesRead;
    190     mFramesUnderrunCount += framesLeft;
    191     // Zero out any samples we could not set.
    192     if (framesLeft > 0) {
    193         mUnderrunCount++;
    194         int32_t bytesToZero = convertFramesToBytes(framesLeft);
    195         memset(buffer, 0, bytesToZero);
    196     }
    197 
    198     return framesRead;
    199 }
    200 
    201 fifo_frames_t FifoBuffer::getThreshold() {
    202     return mFifo->getThreshold();
    203 }
    204 
    205 void FifoBuffer::setThreshold(fifo_frames_t threshold) {
    206     mFifo->setThreshold(threshold);
    207 }
    208 
    209 fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
    210     return mFifo->getCapacity();
    211 }
    212 
    213 void FifoBuffer::eraseMemory() {
    214     int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
    215     if (numBytes > 0) {
    216         memset(mStorage, 0, (size_t) numBytes);
    217     }
    218 }
    219