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 #include <memory>
27
28 #include "FifoControllerBase.h"
29 #include "FifoController.h"
30 #include "FifoControllerIndirect.h"
31 #include "FifoBuffer.h"
32
33 using android::FifoBuffer;
34 using android::fifo_frames_t;
35
FifoBuffer(int32_t bytesPerFrame,fifo_frames_t capacityInFrames)36 FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
37 : mBytesPerFrame(bytesPerFrame)
38 {
39 mFifo = std::make_unique<FifoController>(capacityInFrames, capacityInFrames);
40 // allocate buffer
41 int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
42 mStorage = new uint8_t[bytesPerBuffer];
43 mStorageOwned = true;
44 ALOGV("%s() capacityInFrames = %d, bytesPerFrame = %d",
45 __func__, capacityInFrames, bytesPerFrame);
46 }
47
FifoBuffer(int32_t bytesPerFrame,fifo_frames_t capacityInFrames,fifo_counter_t * readIndexAddress,fifo_counter_t * writeIndexAddress,void * dataStorageAddress)48 FifoBuffer::FifoBuffer( int32_t bytesPerFrame,
49 fifo_frames_t capacityInFrames,
50 fifo_counter_t * readIndexAddress,
51 fifo_counter_t * writeIndexAddress,
52 void * dataStorageAddress
53 )
54 : mBytesPerFrame(bytesPerFrame)
55 , mStorage(static_cast<uint8_t *>(dataStorageAddress))
56 {
57 mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
58 capacityInFrames,
59 readIndexAddress,
60 writeIndexAddress);
61 mStorageOwned = false;
62 }
63
~FifoBuffer()64 FifoBuffer::~FifoBuffer() {
65 if (mStorageOwned) {
66 delete[] mStorage;
67 }
68 }
69
convertFramesToBytes(fifo_frames_t frames)70 int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
71 return frames * mBytesPerFrame;
72 }
73
fillWrappingBuffer(WrappingBuffer * wrappingBuffer,int32_t framesAvailable,int32_t startIndex)74 void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
75 int32_t framesAvailable,
76 int32_t startIndex) {
77 wrappingBuffer->data[1] = nullptr;
78 wrappingBuffer->numFrames[1] = 0;
79 if (framesAvailable > 0) {
80 fifo_frames_t capacity = mFifo->getCapacity();
81 uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
82 // Does the available data cross the end of the FIFO?
83 if ((startIndex + framesAvailable) > capacity) {
84 wrappingBuffer->data[0] = source;
85 fifo_frames_t firstFrames = capacity - startIndex;
86 wrappingBuffer->numFrames[0] = firstFrames;
87 wrappingBuffer->data[1] = &mStorage[0];
88 wrappingBuffer->numFrames[1] = framesAvailable - firstFrames;
89 } else {
90 wrappingBuffer->data[0] = source;
91 wrappingBuffer->numFrames[0] = framesAvailable;
92 }
93 } else {
94 wrappingBuffer->data[0] = nullptr;
95 wrappingBuffer->numFrames[0] = 0;
96 }
97 }
98
getFullDataAvailable(WrappingBuffer * wrappingBuffer)99 fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
100 // The FIFO might be overfull so clip to capacity.
101 fifo_frames_t framesAvailable = std::min(mFifo->getFullFramesAvailable(),
102 mFifo->getCapacity());
103 fifo_frames_t startIndex = mFifo->getReadIndex();
104 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
105 return framesAvailable;
106 }
107
getEmptyRoomAvailable(WrappingBuffer * wrappingBuffer)108 fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
109 // The FIFO might have underrun so clip to capacity.
110 fifo_frames_t framesAvailable = std::min(mFifo->getEmptyFramesAvailable(),
111 mFifo->getCapacity());
112 fifo_frames_t startIndex = mFifo->getWriteIndex();
113 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
114 return framesAvailable;
115 }
116
read(void * buffer,fifo_frames_t numFrames)117 fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
118 WrappingBuffer wrappingBuffer;
119 uint8_t *destination = (uint8_t *) buffer;
120 fifo_frames_t framesLeft = numFrames;
121
122 getFullDataAvailable(&wrappingBuffer);
123
124 // Read data in one or two parts.
125 int partIndex = 0;
126 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
127 fifo_frames_t framesToRead = framesLeft;
128 fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
129 if (framesAvailable > 0) {
130 if (framesToRead > framesAvailable) {
131 framesToRead = framesAvailable;
132 }
133 int32_t numBytes = convertFramesToBytes(framesToRead);
134 memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
135
136 destination += numBytes;
137 framesLeft -= framesToRead;
138 } else {
139 break;
140 }
141 partIndex++;
142 }
143 fifo_frames_t framesRead = numFrames - framesLeft;
144 mFifo->advanceReadIndex(framesRead);
145 return framesRead;
146 }
147
write(const void * buffer,fifo_frames_t numFrames)148 fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) {
149 WrappingBuffer wrappingBuffer;
150 uint8_t *source = (uint8_t *) buffer;
151 fifo_frames_t framesLeft = numFrames;
152
153 getEmptyRoomAvailable(&wrappingBuffer);
154
155 // Read data in one or two parts.
156 int partIndex = 0;
157 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
158 fifo_frames_t framesToWrite = framesLeft;
159 fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
160 if (framesAvailable > 0) {
161 if (framesToWrite > framesAvailable) {
162 framesToWrite = framesAvailable;
163 }
164 int32_t numBytes = convertFramesToBytes(framesToWrite);
165 memcpy(wrappingBuffer.data[partIndex], source, numBytes);
166
167 source += numBytes;
168 framesLeft -= framesToWrite;
169 } else {
170 break;
171 }
172 partIndex++;
173 }
174 fifo_frames_t framesWritten = numFrames - framesLeft;
175 mFifo->advanceWriteIndex(framesWritten);
176 return framesWritten;
177 }
178
getThreshold()179 fifo_frames_t FifoBuffer::getThreshold() {
180 return mFifo->getThreshold();
181 }
182
setThreshold(fifo_frames_t threshold)183 void FifoBuffer::setThreshold(fifo_frames_t threshold) {
184 mFifo->setThreshold(threshold);
185 }
186
getBufferCapacityInFrames()187 fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
188 return mFifo->getCapacity();
189 }
190
eraseMemory()191 void FifoBuffer::eraseMemory() {
192 int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
193 if (numBytes > 0) {
194 memset(mStorage, 0, (size_t) numBytes);
195 }
196 }
197