• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FifoBuffer(int32_t bytesPerFrame,fifo_frames_t capacityInFrames)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     ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
49           capacityInFrames, bytesPerFrame);
50 }
51 
FifoBuffer(int32_t bytesPerFrame,fifo_frames_t capacityInFrames,fifo_counter_t * readIndexAddress,fifo_counter_t * writeIndexAddress,void * dataStorageAddress)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 
~FifoBuffer()72 FifoBuffer::~FifoBuffer() {
73     if (mStorageOwned) {
74         delete[] mStorage;
75     }
76     delete mFifo;
77 }
78 
79 
convertFramesToBytes(fifo_frames_t frames)80 int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
81     return frames * mBytesPerFrame;
82 }
83 
fillWrappingBuffer(WrappingBuffer * wrappingBuffer,int32_t framesAvailable,int32_t startIndex)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 
getFullDataAvailable(WrappingBuffer * wrappingBuffer)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 
getEmptyRoomAvailable(WrappingBuffer * wrappingBuffer)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 
read(void * buffer,fifo_frames_t numFrames)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 
write(const void * buffer,fifo_frames_t numFrames)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 
readNow(void * buffer,fifo_frames_t numFrames)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 
getThreshold()203 fifo_frames_t FifoBuffer::getThreshold() {
204     return mFifo->getThreshold();
205 }
206 
setThreshold(fifo_frames_t threshold)207 void FifoBuffer::setThreshold(fifo_frames_t threshold) {
208     mFifo->setThreshold(threshold);
209 }
210 
getBufferCapacityInFrames()211 fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
212     return mFifo->getCapacity();
213 }
214 
eraseMemory()215 void FifoBuffer::eraseMemory() {
216     int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
217     if (numBytes > 0) {
218         memset(mStorage, 0, (size_t) numBytes);
219     }
220 }
221