blob: 958bbfbdaacb23b6175a7ee2d450fa11b625c019 [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) {
Glenn Kastena7a0e042016-06-17 10:53:09 -0700199 ALOG_ASSERT(fifo.mThrottleFront == NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700200 fifo.mThrottleFront = &mSharedFront;
201 }
202}
203
204audio_utils_fifo_reader::~audio_utils_fifo_reader()
205{
Glenn Kastena7a0e042016-06-17 10:53:09 -0700206 if (mFifo.mThrottleFront == &mSharedFront) {
207 mFifo.mThrottleFront = NULL;
208 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700209}
210
211ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700212 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800213{
Glenn Kasten547a9922016-06-15 13:07:31 -0700214 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700215 ssize_t availToRead = obtain(iovec, count, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700216 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700217 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
218 iovec[0].mLength * mFifo.mFrameSize);
219 if (iovec[1].mLength > 0) {
220 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
221 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
222 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700223 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700224 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700225 }
226 return availToRead;
227}
228
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700229ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700230 __attribute__((no_sanitize("integer")))
231{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700232 return obtain(iovec, count, NULL);
233}
234
235void audio_utils_fifo_reader::release(size_t count)
236 __attribute__((no_sanitize("integer")))
237{
238 if (count > 0) {
239 ALOG_ASSERT(count <= mObtained);
240 mLocalFront = mFifo.sum(mLocalFront, count);
241 if (mFifo.mThrottleFront == &mSharedFront) {
242 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
243 std::memory_order_release);
244 }
245 mObtained -= count;
246 }
247}
248
249ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, size_t *lost)
250 __attribute__((no_sanitize("integer")))
251{
252 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
253 std::memory_order_acquire);
254 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700255 if (filled < 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700256 if (filled == android::BAD_INDEX) {
257 mLocalFront = rear;
258 }
259 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700260 return (ssize_t) filled;
261 }
262 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800263 if (availToRead > count) {
264 availToRead = count;
265 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700266 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
267 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800268 if (part1 > availToRead) {
269 part1 = availToRead;
270 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700271 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700272 iovec[0].mOffset = frontMasked;
273 iovec[0].mLength = part1;
274 iovec[1].mOffset = 0;
275 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700276 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700277 return availToRead;
278}