FifoBuffer.cpp revision c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fb
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 30using namespace android; // TODO just import names needed 31 32FifoBuffer::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 50FifoBuffer::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 // TODO Handle possible failures to allocate. Move out of constructor? 64 mFifo = new FifoControllerIndirect(capacityInFrames, 65 capacityInFrames, 66 readIndexAddress, 67 writeIndexAddress); 68 mStorageOwned = false; 69 ALOGD("FifoProcessor: capacityInFrames = %d, bytesPerFrame = %d", 70 capacityInFrames, bytesPerFrame); 71} 72 73FifoBuffer::~FifoBuffer() { 74 if (mStorageOwned) { 75 delete[] mStorage; 76 } 77 delete mFifo; 78} 79 80 81int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) { 82 return frames * mBytesPerFrame; 83} 84 85void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer, 86 int32_t framesAvailable, 87 int32_t startIndex) { 88 wrappingBuffer->data[1] = nullptr; 89 wrappingBuffer->numFrames[1] = 0; 90 if (framesAvailable > 0) { 91 92 uint8_t *source = &mStorage[convertFramesToBytes(startIndex)]; 93 // Does the available data cross the end of the FIFO? 94 if ((startIndex + framesAvailable) > mFrameCapacity) { 95 wrappingBuffer->data[0] = source; 96 wrappingBuffer->numFrames[0] = mFrameCapacity - startIndex; 97 wrappingBuffer->data[1] = &mStorage[0]; 98 wrappingBuffer->numFrames[1] = mFrameCapacity - startIndex; 99 100 } else { 101 wrappingBuffer->data[0] = source; 102 wrappingBuffer->numFrames[0] = framesAvailable; 103 } 104 } else { 105 wrappingBuffer->data[0] = nullptr; 106 wrappingBuffer->numFrames[0] = 0; 107 } 108 109} 110 111void FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) { 112 fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable(); 113 fifo_frames_t startIndex = mFifo->getReadIndex(); 114 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex); 115} 116 117void FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) { 118 fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable(); 119 fifo_frames_t startIndex = mFifo->getWriteIndex(); 120 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex); 121} 122 123fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) { 124 WrappingBuffer wrappingBuffer; 125 uint8_t *destination = (uint8_t *) buffer; 126 fifo_frames_t framesLeft = numFrames; 127 128 getFullDataAvailable(&wrappingBuffer); 129 130 // Read data in one or two parts. 131 int partIndex = 0; 132 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 133 fifo_frames_t framesToRead = framesLeft; 134 fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 135 //ALOGD("FifoProcessor::read() framesAvailable = %d, partIndex = %d", 136 // framesAvailable, partIndex); 137 if (framesAvailable > 0) { 138 if (framesToRead > framesAvailable) { 139 framesToRead = framesAvailable; 140 } 141 int32_t numBytes = convertFramesToBytes(framesToRead); 142 memcpy(destination, wrappingBuffer.data[partIndex], numBytes); 143 144 destination += numBytes; 145 framesLeft -= framesToRead; 146 } 147 partIndex++; 148 } 149 fifo_frames_t framesRead = numFrames - framesLeft; 150 mFifo->advanceReadIndex(framesRead); 151 return framesRead; 152} 153 154fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) { 155 WrappingBuffer wrappingBuffer; 156 uint8_t *source = (uint8_t *) buffer; 157 fifo_frames_t framesLeft = numFrames; 158 159 getEmptyRoomAvailable(&wrappingBuffer); 160 161 // Read data in one or two parts. 162 int partIndex = 0; 163 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 164 fifo_frames_t framesToWrite = framesLeft; 165 fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 166 if (framesAvailable > 0) { 167 if (framesToWrite > framesAvailable) { 168 framesToWrite = framesAvailable; 169 } 170 int32_t numBytes = convertFramesToBytes(framesToWrite); 171 memcpy(wrappingBuffer.data[partIndex], source, numBytes); 172 173 source += numBytes; 174 framesLeft -= framesToWrite; 175 } 176 partIndex++; 177 } 178 fifo_frames_t framesWritten = numFrames - framesLeft; 179 mFifo->advanceWriteIndex(framesWritten); 180 return framesWritten; 181} 182 183fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) { 184 mLastReadSize = numFrames; 185 fifo_frames_t framesLeft = numFrames; 186 fifo_frames_t framesRead = read(buffer, numFrames); 187 framesLeft -= framesRead; 188 mFramesReadCount += framesRead; 189 mFramesUnderrunCount += framesLeft; 190 // Zero out any samples we could not set. 191 if (framesLeft > 0) { 192 mUnderrunCount++; 193 int32_t bytesToZero = convertFramesToBytes(framesLeft); 194 memset(buffer, 0, bytesToZero); 195 } 196 197 return framesRead; 198} 199 200fifo_frames_t FifoBuffer::getThreshold() { 201 return mFifo->getThreshold(); 202} 203 204void FifoBuffer::setThreshold(fifo_frames_t threshold) { 205 mFifo->setThreshold(threshold); 206} 207 208fifo_frames_t FifoBuffer::getBufferCapacityInFrames() { 209 return mFifo->getCapacity(); 210} 211 212