blob: f5113f2d3ec7cc849ed01a6fd40385f2cc2858c0 [file] [log] [blame]
Phil Burkfd911c12017-01-03 17:15:39 -08001/*
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
Phil Burkc0c70e32017-02-09 13:18:38 -080020
Phil Burkfd911c12017-01-03 17:15:39 -080021#define LOG_TAG "FifoBuffer"
22//#define LOG_NDEBUG 0
23#include <utils/Log.h>
24
Phil Burkf7da0b92018-04-20 17:24:38 -070025#include <algorithm>
Phil Burk882c5202018-04-23 10:32:45 -070026#include <memory>
Phil Burkf7da0b92018-04-20 17:24:38 -070027
Phil Burkfd911c12017-01-03 17:15:39 -080028#include "FifoControllerBase.h"
29#include "FifoController.h"
30#include "FifoControllerIndirect.h"
31#include "FifoBuffer.h"
32
Phil Burk882c5202018-04-23 10:32:45 -070033using android::FifoBuffer;
34using android::fifo_frames_t;
Phil Burkc0c70e32017-02-09 13:18:38 -080035
Phil Burkfd911c12017-01-03 17:15:39 -080036FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
Phil Burk882c5202018-04-23 10:32:45 -070037 : mBytesPerFrame(bytesPerFrame)
Phil Burkfd911c12017-01-03 17:15:39 -080038{
Phil Burk882c5202018-04-23 10:32:45 -070039 mFifo = std::make_unique<FifoController>(capacityInFrames, capacityInFrames);
Phil Burkfd911c12017-01-03 17:15:39 -080040 // allocate buffer
41 int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
42 mStorage = new uint8_t[bytesPerBuffer];
43 mStorageOwned = true;
Phil Burk882c5202018-04-23 10:32:45 -070044 ALOGV("%s() capacityInFrames = %d, bytesPerFrame = %d",
45 __func__, capacityInFrames, bytesPerFrame);
Phil Burkfd911c12017-01-03 17:15:39 -080046}
47
48FifoBuffer::FifoBuffer( int32_t bytesPerFrame,
49 fifo_frames_t capacityInFrames,
50 fifo_counter_t * readIndexAddress,
51 fifo_counter_t * writeIndexAddress,
52 void * dataStorageAddress
53 )
Phil Burk882c5202018-04-23 10:32:45 -070054 : mBytesPerFrame(bytesPerFrame)
Phil Burkfd911c12017-01-03 17:15:39 -080055 , mStorage(static_cast<uint8_t *>(dataStorageAddress))
Phil Burkfd911c12017-01-03 17:15:39 -080056{
Phil Burk882c5202018-04-23 10:32:45 -070057 mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
Phil Burkfd911c12017-01-03 17:15:39 -080058 capacityInFrames,
59 readIndexAddress,
60 writeIndexAddress);
61 mStorageOwned = false;
Phil Burkfd911c12017-01-03 17:15:39 -080062}
63
64FifoBuffer::~FifoBuffer() {
65 if (mStorageOwned) {
66 delete[] mStorage;
67 }
Phil Burkfd911c12017-01-03 17:15:39 -080068}
69
Phil Burkfd911c12017-01-03 17:15:39 -080070int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
71 return frames * mBytesPerFrame;
72}
73
Phil Burkc0c70e32017-02-09 13:18:38 -080074void 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) {
Phil Burk882c5202018-04-23 10:32:45 -070080 fifo_frames_t capacity = mFifo->getCapacity();
Phil Burkc0c70e32017-02-09 13:18:38 -080081 uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
82 // Does the available data cross the end of the FIFO?
Phil Burk882c5202018-04-23 10:32:45 -070083 if ((startIndex + framesAvailable) > capacity) {
Phil Burkc0c70e32017-02-09 13:18:38 -080084 wrappingBuffer->data[0] = source;
Phil Burk882c5202018-04-23 10:32:45 -070085 fifo_frames_t firstFrames = capacity - startIndex;
Phil Burkf7da0b92018-04-20 17:24:38 -070086 wrappingBuffer->numFrames[0] = firstFrames;
Phil Burkc0c70e32017-02-09 13:18:38 -080087 wrappingBuffer->data[1] = &mStorage[0];
Phil Burkf7da0b92018-04-20 17:24:38 -070088 wrappingBuffer->numFrames[1] = framesAvailable - firstFrames;
Phil Burkc0c70e32017-02-09 13:18:38 -080089 } else {
90 wrappingBuffer->data[0] = source;
91 wrappingBuffer->numFrames[0] = framesAvailable;
92 }
Phil Burkfd911c12017-01-03 17:15:39 -080093 } else {
Phil Burkc0c70e32017-02-09 13:18:38 -080094 wrappingBuffer->data[0] = nullptr;
95 wrappingBuffer->numFrames[0] = 0;
Phil Burkfd911c12017-01-03 17:15:39 -080096 }
Phil Burkfd911c12017-01-03 17:15:39 -080097}
98
Phil Burkfd34a932017-07-19 07:03:52 -070099fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
Phil Burkf7da0b92018-04-20 17:24:38 -0700100 // The FIFO might be overfull so clip to capacity.
Phil Burk882c5202018-04-23 10:32:45 -0700101 fifo_frames_t framesAvailable = std::min(mFifo->getFullFramesAvailable(),
102 mFifo->getCapacity());
Phil Burkc0c70e32017-02-09 13:18:38 -0800103 fifo_frames_t startIndex = mFifo->getReadIndex();
104 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
Phil Burkfd34a932017-07-19 07:03:52 -0700105 return framesAvailable;
Phil Burkc0c70e32017-02-09 13:18:38 -0800106}
107
Phil Burkfd34a932017-07-19 07:03:52 -0700108fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
Phil Burkf7da0b92018-04-20 17:24:38 -0700109 // The FIFO might have underrun so clip to capacity.
Phil Burk882c5202018-04-23 10:32:45 -0700110 fifo_frames_t framesAvailable = std::min(mFifo->getEmptyFramesAvailable(),
111 mFifo->getCapacity());
Phil Burkc0c70e32017-02-09 13:18:38 -0800112 fifo_frames_t startIndex = mFifo->getWriteIndex();
113 fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
Phil Burkfd34a932017-07-19 07:03:52 -0700114 return framesAvailable;
Phil Burkc0c70e32017-02-09 13:18:38 -0800115}
Phil Burkfd911c12017-01-03 17:15:39 -0800116
Phil Burkc0c70e32017-02-09 13:18:38 -0800117fifo_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;
Phil Burkfd911c12017-01-03 17:15:39 -0800121
Phil Burkc0c70e32017-02-09 13:18:38 -0800122 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];
Phil Burkc0c70e32017-02-09 13:18:38 -0800129 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;
Phil Burk71f35bb2017-04-13 16:05:07 -0700138 } else {
139 break;
Phil Burkc0c70e32017-02-09 13:18:38 -0800140 }
141 partIndex++;
142 }
143 fifo_frames_t framesRead = numFrames - framesLeft;
144 mFifo->advanceReadIndex(framesRead);
145 return framesRead;
146}
147
148fifo_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;
Phil Burk71f35bb2017-04-13 16:05:07 -0700169 } else {
170 break;
Phil Burkc0c70e32017-02-09 13:18:38 -0800171 }
172 partIndex++;
173 }
174 fifo_frames_t framesWritten = numFrames - framesLeft;
175 mFifo->advanceWriteIndex(framesWritten);
176 return framesWritten;
Phil Burkfd911c12017-01-03 17:15:39 -0800177}
178
Phil Burkfd911c12017-01-03 17:15:39 -0800179fifo_frames_t FifoBuffer::getThreshold() {
180 return mFifo->getThreshold();
181}
182
183void FifoBuffer::setThreshold(fifo_frames_t threshold) {
184 mFifo->setThreshold(threshold);
185}
186
187fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
188 return mFifo->getCapacity();
189}
190
Phil Burkea04d972017-08-07 12:30:44 -0700191void FifoBuffer::eraseMemory() {
192 int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
193 if (numBytes > 0) {
194 memset(mStorage, 0, (size_t) numBytes);
195 }
196}