blob: ec71d5f31eb4d7fbab77e39da6a715b6d23c4139 [file] [log] [blame]
Glenn Kasten9b4c8052015-01-06 14:13:13 -08001/*
2 * Copyright (C) 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//#define LOG_NDEBUG 0
18#define LOG_TAG "audio_utils_fifo"
19
20#include <stdlib.h>
21#include <string.h>
22#include <audio_utils/fifo.h>
23#include <audio_utils/roundup.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080024#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070025#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080026
Glenn Kasten09acf782016-06-17 10:28:05 -070027audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070028 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070029 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070030 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kasten6d7ad762016-06-15 17:05:54 -070031 mSharedRear(0), mThrottleFront(NULL)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080032{
Glenn Kasten09acf782016-06-17 10:28:05 -070033 // actual upper bound on frameCount will depend on the frame size
34 ALOG_ASSERT(frameCount > 0 && frameCount <= ((uint32_t) INT_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080035}
36
Glenn Kasten09acf782016-06-17 10:28:05 -070037audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080038{
39}
40
Glenn Kasten09acf782016-06-17 10:28:05 -070041uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070042 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080043{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070044 if (mFudgeFactor) {
45 uint32_t mask = mFrameCountP2 - 1;
46 ALOG_ASSERT((index & mask) < mFrameCount);
47 ALOG_ASSERT(increment <= mFrameCountP2);
48 if ((index & mask) + increment >= mFrameCount) {
49 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080050 }
51 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070052 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080053 return index;
54 } else {
55 return index + increment;
56 }
57}
58
Glenn Kasten09acf782016-06-17 10:28:05 -070059int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070060 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080061{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070062 uint32_t diff = rear - front;
63 if (mFudgeFactor) {
64 uint32_t mask = mFrameCountP2 - 1;
65 uint32_t rearMasked = rear & mask;
66 uint32_t frontMasked = front & mask;
67 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070068 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070069 }
70 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080071 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070072 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070073 if (lost != NULL) {
74 // TODO provide a more accurate estimate
75 *lost = (genDiff / mFrameCountP2) * mFrameCount;
76 }
77 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070078 }
79 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080080 }
81 }
82 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -070083 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070084 if (lost != NULL) {
85 *lost = diff - mFrameCount;
86 }
87 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070088 }
89 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080090}
91
Glenn Kasten6d7ad762016-06-15 17:05:54 -070092////////////////////////////////////////////////////////////////////////////////
93
Glenn Kasten09acf782016-06-17 10:28:05 -070094audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer)
95 __attribute__((no_sanitize("integer"))) :
96 audio_utils_fifo_base(frameCount), mFrameSize(frameSize), mBuffer(buffer)
97{
98 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
99 // be able to distinguish successful and error return values from read and write.
100 ALOG_ASSERT(frameCount > 0 && frameSize > 0 && buffer != NULL &&
101 frameCount <= ((uint32_t) INT_MAX) / frameSize);
102}
103
104audio_utils_fifo::~audio_utils_fifo()
105{
106}
107
108////////////////////////////////////////////////////////////////////////////////
109
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700110audio_utils_fifo_provider::audio_utils_fifo_provider() :
111 mObtained(0)
112{
113}
114
115audio_utils_fifo_provider::~audio_utils_fifo_provider()
116{
117}
118
119////////////////////////////////////////////////////////////////////////////////
120
121audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
122 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0)
123{
124}
125
126audio_utils_fifo_writer::~audio_utils_fifo_writer()
127{
128}
129
130ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700131 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800132{
Glenn Kasten547a9922016-06-15 13:07:31 -0700133 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700134 ssize_t availToWrite = obtain(iovec, count);
Glenn Kasten547a9922016-06-15 13:07:31 -0700135 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700136 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
137 iovec[0].mLength * mFifo.mFrameSize);
138 if (iovec[1].mLength > 0) {
139 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
140 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
141 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700142 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700143 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700144 }
145 return availToWrite;
146}
147
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700148ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700149 __attribute__((no_sanitize("integer")))
150{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700151 size_t availToWrite;
152 if (mFifo.mThrottleFront != NULL) {
153 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
154 std::memory_order_acquire);
155 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
156 if (filled < 0) {
157 mObtained = 0;
158 return (ssize_t) filled;
159 }
160 availToWrite = (size_t) mFifo.mFrameCount - (size_t) filled;
161 } else {
162 availToWrite = mFifo.mFrameCount;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700163 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800164 if (availToWrite > count) {
165 availToWrite = count;
166 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700167 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
168 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800169 if (part1 > availToWrite) {
170 part1 = availToWrite;
171 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700172 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700173 iovec[0].mOffset = rearMasked;
174 iovec[0].mLength = part1;
175 iovec[1].mOffset = 0;
176 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700177 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800178 return availToWrite;
179}
180
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700181void audio_utils_fifo_writer::release(size_t count)
182 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700183{
184 if (count > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700185 ALOG_ASSERT(count <= mObtained);
186 mLocalRear = mFifo.sum(mLocalRear, count);
187 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
Glenn Kasten547a9922016-06-15 13:07:31 -0700188 std::memory_order_release);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700189 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700190 }
191}
192
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700193////////////////////////////////////////////////////////////////////////////////
194
195audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
196 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0)
197{
198 if (throttlesWriter) {
199 fifo.mThrottleFront = &mSharedFront;
200 }
201}
202
203audio_utils_fifo_reader::~audio_utils_fifo_reader()
204{
205}
206
207ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700208 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800209{
Glenn Kasten547a9922016-06-15 13:07:31 -0700210 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700211 ssize_t availToRead = obtain(iovec, count, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700212 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700213 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
214 iovec[0].mLength * mFifo.mFrameSize);
215 if (iovec[1].mLength > 0) {
216 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
217 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
218 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700219 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700220 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700221 }
222 return availToRead;
223}
224
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700225ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700226 __attribute__((no_sanitize("integer")))
227{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700228 return obtain(iovec, count, NULL);
229}
230
231void audio_utils_fifo_reader::release(size_t count)
232 __attribute__((no_sanitize("integer")))
233{
234 if (count > 0) {
235 ALOG_ASSERT(count <= mObtained);
236 mLocalFront = mFifo.sum(mLocalFront, count);
237 if (mFifo.mThrottleFront == &mSharedFront) {
238 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
239 std::memory_order_release);
240 }
241 mObtained -= count;
242 }
243}
244
245ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, size_t *lost)
246 __attribute__((no_sanitize("integer")))
247{
248 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
249 std::memory_order_acquire);
250 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700251 if (filled < 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700252 if (filled == android::BAD_INDEX) {
253 mLocalFront = rear;
254 }
255 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700256 return (ssize_t) filled;
257 }
258 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800259 if (availToRead > count) {
260 availToRead = count;
261 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700262 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
263 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800264 if (part1 > availToRead) {
265 part1 = availToRead;
266 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700267 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700268 iovec[0].mOffset = frontMasked;
269 iovec[0].mLength = part1;
270 iovec[1].mOffset = 0;
271 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700272 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700273 return availToRead;
274}