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 mFifo = new FifoControllerIndirect(capacityInFrames, 64 capacityInFrames, 65 readIndexAddress, 66 writeIndexAddress); 67 mStorageOwned = false; 68} 69 70FifoBuffer::~FifoBuffer() { 71 if (mStorageOwned) { 72 delete[] mStorage; 73 } 74 delete mFifo; 75} 76 77 78int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) { 79 return frames * mBytesPerFrame; 80} 81 82void 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 108void FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) { 109 fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable(); 110 fifo_frames_t startIndex = mFifo->getReadIndex(); 111 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex); 112} 113 114void FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) { 115 fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable(); 116 fifo_frames_t startIndex = mFifo->getWriteIndex(); 117 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex); 118} 119 120fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) { 121 WrappingBuffer wrappingBuffer; 122 uint8_t *destination = (uint8_t *) buffer; 123 fifo_frames_t framesLeft = numFrames; 124 125 getFullDataAvailable(&wrappingBuffer); 126 127 // Read data in one or two parts. 128 int partIndex = 0; 129 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 130 fifo_frames_t framesToRead = framesLeft; 131 fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 132 if (framesAvailable > 0) { 133 if (framesToRead > framesAvailable) { 134 framesToRead = framesAvailable; 135 } 136 int32_t numBytes = convertFramesToBytes(framesToRead); 137 memcpy(destination, wrappingBuffer.data[partIndex], numBytes); 138 139 destination += numBytes; 140 framesLeft -= framesToRead; 141 } else { 142 break; 143 } 144 partIndex++; 145 } 146 fifo_frames_t framesRead = numFrames - framesLeft; 147 mFifo->advanceReadIndex(framesRead); 148 return framesRead; 149} 150 151fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) { 152 WrappingBuffer wrappingBuffer; 153 uint8_t *source = (uint8_t *) buffer; 154 fifo_frames_t framesLeft = numFrames; 155 156 getEmptyRoomAvailable(&wrappingBuffer); 157 158 // Read data in one or two parts. 159 int partIndex = 0; 160 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 161 fifo_frames_t framesToWrite = framesLeft; 162 fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 163 if (framesAvailable > 0) { 164 if (framesToWrite > framesAvailable) { 165 framesToWrite = framesAvailable; 166 } 167 int32_t numBytes = convertFramesToBytes(framesToWrite); 168 memcpy(wrappingBuffer.data[partIndex], source, numBytes); 169 170 source += numBytes; 171 framesLeft -= framesToWrite; 172 } else { 173 break; 174 } 175 partIndex++; 176 } 177 fifo_frames_t framesWritten = numFrames - framesLeft; 178 mFifo->advanceWriteIndex(framesWritten); 179 return framesWritten; 180} 181 182fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) { 183 mLastReadSize = numFrames; 184 fifo_frames_t framesLeft = numFrames; 185 fifo_frames_t framesRead = read(buffer, numFrames); 186 framesLeft -= framesRead; 187 mFramesReadCount += framesRead; 188 mFramesUnderrunCount += framesLeft; 189 // Zero out any samples we could not set. 190 if (framesLeft > 0) { 191 mUnderrunCount++; 192 int32_t bytesToZero = convertFramesToBytes(framesLeft); 193 memset(buffer, 0, bytesToZero); 194 } 195 196 return framesRead; 197} 198 199fifo_frames_t FifoBuffer::getThreshold() { 200 return mFifo->getThreshold(); 201} 202 203void FifoBuffer::setThreshold(fifo_frames_t threshold) { 204 mFifo->setThreshold(threshold); 205} 206 207fifo_frames_t FifoBuffer::getBufferCapacityInFrames() { 208 return mFifo->getCapacity(); 209} 210 211