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