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