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 <algorithm>
     26 
     27 #include "FifoControllerBase.h"
     28 #include "FifoController.h"
     29 #include "FifoControllerIndirect.h"
     30 #include "FifoBuffer.h"
     31 
     32 using namespace android; // TODO just import names needed
     33 
     34 FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
     35         : mFrameCapacity(capacityInFrames)
     36         , mBytesPerFrame(bytesPerFrame)
     37         , mStorage(nullptr)
     38         , mFramesReadCount(0)
     39         , mFramesUnderrunCount(0)
     40         , mUnderrunCount(0)
     41 {
     42     // TODO Handle possible failures to allocate. Move out of constructor?
     43     mFifo = new FifoController(capacityInFrames, capacityInFrames);
     44     // allocate buffer
     45     int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
     46     mStorage = new uint8_t[bytesPerBuffer];
     47     mStorageOwned = true;
     48     ALOGV("capacityInFrames = %d, bytesPerFrame = %d",
     49           capacityInFrames, bytesPerFrame);
     50 }
     51 
     52 FifoBuffer::FifoBuffer( int32_t   bytesPerFrame,
     53                         fifo_frames_t   capacityInFrames,
     54                         fifo_counter_t *  readIndexAddress,
     55                         fifo_counter_t *  writeIndexAddress,
     56                         void *  dataStorageAddress
     57                         )
     58         : mFrameCapacity(capacityInFrames)
     59         , mBytesPerFrame(bytesPerFrame)
     60         , mStorage(static_cast<uint8_t *>(dataStorageAddress))
     61         , mFramesReadCount(0)
     62         , mFramesUnderrunCount(0)
     63         , mUnderrunCount(0)
     64 {
     65     mFifo = new FifoControllerIndirect(capacityInFrames,
     66                                        capacityInFrames,
     67                                        readIndexAddress,
     68                                        writeIndexAddress);
     69     mStorageOwned = false;
     70 }
     71 
     72 FifoBuffer::~FifoBuffer() {
     73     if (mStorageOwned) {
     74         delete[] mStorage;
     75     }
     76     delete mFifo;
     77 }
     78 
     79 
     80 int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
     81     return frames * mBytesPerFrame;
     82 }
     83 
     84 void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
     85                                     int32_t framesAvailable,
     86                                     int32_t startIndex) {
     87     wrappingBuffer->data[1] = nullptr;
     88     wrappingBuffer->numFrames[1] = 0;
     89     if (framesAvailable > 0) {
     90         uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
     91         // Does the available data cross the end of the FIFO?
     92         if ((startIndex + framesAvailable) > mFrameCapacity) {
     93             wrappingBuffer->data[0] = source;
     94             fifo_frames_t firstFrames = mFrameCapacity - startIndex;
     95             wrappingBuffer->numFrames[0] = firstFrames;
     96             wrappingBuffer->data[1] = &mStorage[0];
     97             wrappingBuffer->numFrames[1] = framesAvailable - firstFrames;
     98         } else {
     99             wrappingBuffer->data[0] = source;
    100             wrappingBuffer->numFrames[0] = framesAvailable;
    101         }
    102     } else {
    103         wrappingBuffer->data[0] = nullptr;
    104         wrappingBuffer->numFrames[0] = 0;
    105     }
    106 }
    107 
    108 fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
    109     // The FIFO might be overfull so clip to capacity.
    110     fifo_frames_t framesAvailable = std::min(mFifo->getFullFramesAvailable(), mFrameCapacity);
    111     fifo_frames_t startIndex = mFifo->getReadIndex();
    112     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
    113     return framesAvailable;
    114 }
    115 
    116 fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
    117     // The FIFO might have underrun so clip to capacity.
    118     fifo_frames_t framesAvailable = std::min(mFifo->getEmptyFramesAvailable(), mFrameCapacity);
    119     fifo_frames_t startIndex = mFifo->getWriteIndex();
    120     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
    121     return framesAvailable;
    122 }
    123 
    124 fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
    125     WrappingBuffer wrappingBuffer;
    126     uint8_t *destination = (uint8_t *) buffer;
    127     fifo_frames_t framesLeft = numFrames;
    128 
    129     getFullDataAvailable(&wrappingBuffer);
    130 
    131     // Read data in one or two parts.
    132     int partIndex = 0;
    133     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
    134         fifo_frames_t framesToRead = framesLeft;
    135         fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
    136         if (framesAvailable > 0) {
    137             if (framesToRead > framesAvailable) {
    138                 framesToRead = framesAvailable;
    139             }
    140             int32_t numBytes = convertFramesToBytes(framesToRead);
    141             memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
    142 
    143             destination += numBytes;
    144             framesLeft -= framesToRead;
    145         } else {
    146             break;
    147         }
    148         partIndex++;
    149     }
    150     fifo_frames_t framesRead = numFrames - framesLeft;
    151     mFifo->advanceReadIndex(framesRead);
    152     return framesRead;
    153 }
    154 
    155 fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) {
    156     WrappingBuffer wrappingBuffer;
    157     uint8_t *source = (uint8_t *) buffer;
    158     fifo_frames_t framesLeft = numFrames;
    159 
    160     getEmptyRoomAvailable(&wrappingBuffer);
    161 
    162     // Read data in one or two parts.
    163     int partIndex = 0;
    164     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
    165         fifo_frames_t framesToWrite = framesLeft;
    166         fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
    167         if (framesAvailable > 0) {
    168             if (framesToWrite > framesAvailable) {
    169                 framesToWrite = framesAvailable;
    170             }
    171             int32_t numBytes = convertFramesToBytes(framesToWrite);
    172             memcpy(wrappingBuffer.data[partIndex], source, numBytes);
    173 
    174             source += numBytes;
    175             framesLeft -= framesToWrite;
    176         } else {
    177             break;
    178         }
    179         partIndex++;
    180     }
    181     fifo_frames_t framesWritten = numFrames - framesLeft;
    182     mFifo->advanceWriteIndex(framesWritten);
    183     return framesWritten;
    184 }
    185 
    186 fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
    187     mLastReadSize = numFrames;
    188     fifo_frames_t framesLeft = numFrames;
    189     fifo_frames_t framesRead = read(buffer, numFrames);
    190     framesLeft -= framesRead;
    191     mFramesReadCount += framesRead;
    192     mFramesUnderrunCount += framesLeft;
    193     // Zero out any samples we could not set.
    194     if (framesLeft > 0) {
    195         mUnderrunCount++;
    196         int32_t bytesToZero = convertFramesToBytes(framesLeft);
    197         memset(buffer, 0, bytesToZero);
    198     }
    199 
    200     return framesRead;
    201 }
    202 
    203 fifo_frames_t FifoBuffer::getThreshold() {
    204     return mFifo->getThreshold();
    205 }
    206 
    207 void FifoBuffer::setThreshold(fifo_frames_t threshold) {
    208     mFifo->setThreshold(threshold);
    209 }
    210 
    211 fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
    212     return mFifo->getCapacity();
    213 }
    214 
    215 void FifoBuffer::eraseMemory() {
    216     int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
    217     if (numBytes > 0) {
    218         memset(mStorage, 0, (size_t) numBytes);
    219     }
    220 }
    221