blob: 92e0a9f060bfc2a7de5018b6ef7dc947fa58e611 [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 Kasten6d7ad762016-06-15 17:05:54 -0700136 memcpy(iovec[0].mBase, buffer, iovec[0].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700137 if (iovec[1].mLen > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700138 memcpy(iovec[1].mBase, (char *) buffer + (iovec[0].mLen * mFifo.mFrameSize),
139 iovec[1].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700140 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700141 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700142 }
143 return availToWrite;
144}
145
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700146ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700147 __attribute__((no_sanitize("integer")))
148{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700149 size_t availToWrite;
150 if (mFifo.mThrottleFront != NULL) {
151 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
152 std::memory_order_acquire);
153 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
154 if (filled < 0) {
155 mObtained = 0;
156 return (ssize_t) filled;
157 }
158 availToWrite = (size_t) mFifo.mFrameCount - (size_t) filled;
159 } else {
160 availToWrite = mFifo.mFrameCount;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700161 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800162 if (availToWrite > count) {
163 availToWrite = count;
164 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700165 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
166 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800167 if (part1 > availToWrite) {
168 part1 = availToWrite;
169 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700170 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
171 iovec[0].mLen = part1;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700172 iovec[0].mBase = part1 > 0 ? (char *) mFifo.mBuffer + (rearMasked * mFifo.mFrameSize) : NULL;
Glenn Kasten547a9922016-06-15 13:07:31 -0700173 iovec[1].mLen = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700174 iovec[1].mBase = part2 > 0 ? mFifo.mBuffer : NULL;
175 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800176 return availToWrite;
177}
178
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700179void audio_utils_fifo_writer::release(size_t count)
180 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700181{
182 if (count > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700183 ALOG_ASSERT(count <= mObtained);
184 mLocalRear = mFifo.sum(mLocalRear, count);
185 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
Glenn Kasten547a9922016-06-15 13:07:31 -0700186 std::memory_order_release);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700187 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700188 }
189}
190
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700191////////////////////////////////////////////////////////////////////////////////
192
193audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
194 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0)
195{
196 if (throttlesWriter) {
197 fifo.mThrottleFront = &mSharedFront;
198 }
199}
200
201audio_utils_fifo_reader::~audio_utils_fifo_reader()
202{
203}
204
205ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700206 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800207{
Glenn Kasten547a9922016-06-15 13:07:31 -0700208 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700209 ssize_t availToRead = obtain(iovec, count, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700210 if (availToRead > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700211 memcpy(buffer, iovec[0].mBase, iovec[0].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700212 if (iovec[1].mLen > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700213 memcpy((char *) buffer + (iovec[0].mLen * mFifo.mFrameSize), iovec[1].mBase,
214 iovec[1].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700215 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700216 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700217 }
218 return availToRead;
219}
220
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700221ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700222 __attribute__((no_sanitize("integer")))
223{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700224 return obtain(iovec, count, NULL);
225}
226
227void audio_utils_fifo_reader::release(size_t count)
228 __attribute__((no_sanitize("integer")))
229{
230 if (count > 0) {
231 ALOG_ASSERT(count <= mObtained);
232 mLocalFront = mFifo.sum(mLocalFront, count);
233 if (mFifo.mThrottleFront == &mSharedFront) {
234 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
235 std::memory_order_release);
236 }
237 mObtained -= count;
238 }
239}
240
241ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, size_t *lost)
242 __attribute__((no_sanitize("integer")))
243{
244 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
245 std::memory_order_acquire);
246 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700247 if (filled < 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700248 if (filled == android::BAD_INDEX) {
249 mLocalFront = rear;
250 }
251 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700252 return (ssize_t) filled;
253 }
254 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800255 if (availToRead > count) {
256 availToRead = count;
257 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700258 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
259 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800260 if (part1 > availToRead) {
261 part1 = availToRead;
262 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700263 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
264 iovec[0].mLen = part1;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700265 iovec[0].mBase = part1 > 0 ? (char *) mFifo.mBuffer + (frontMasked * mFifo.mFrameSize) : NULL;
Glenn Kasten547a9922016-06-15 13:07:31 -0700266 iovec[1].mLen = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700267 iovec[1].mBase = part2 > 0 ? mFifo.mBuffer : NULL;
268 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700269 return availToRead;
270}