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