blob: 31c614d788846efd938a1ae961cf6413cb5f9900 [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
Glenn Kasten0ab1d862016-06-20 12:04:56 -070020#include <limits.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080021#include <stdlib.h>
22#include <string.h>
23#include <audio_utils/fifo.h>
24#include <audio_utils/roundup.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080025#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070026#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080027
Glenn Kasten09acf782016-06-17 10:28:05 -070028audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070029 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070030 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070031 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kasten6d7ad762016-06-15 17:05:54 -070032 mSharedRear(0), mThrottleFront(NULL)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080033{
Glenn Kasten09acf782016-06-17 10:28:05 -070034 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten0ab1d862016-06-20 12:04:56 -070035 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080036}
37
Glenn Kasten09acf782016-06-17 10:28:05 -070038audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080039{
40}
41
Glenn Kasten09acf782016-06-17 10:28:05 -070042uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070043 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080044{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070045 if (mFudgeFactor) {
46 uint32_t mask = mFrameCountP2 - 1;
47 ALOG_ASSERT((index & mask) < mFrameCount);
48 ALOG_ASSERT(increment <= mFrameCountP2);
49 if ((index & mask) + increment >= mFrameCount) {
50 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080051 }
52 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070053 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080054 return index;
55 } else {
56 return index + increment;
57 }
58}
59
Glenn Kasten09acf782016-06-17 10:28:05 -070060int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070061 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080062{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070063 uint32_t diff = rear - front;
64 if (mFudgeFactor) {
65 uint32_t mask = mFrameCountP2 - 1;
66 uint32_t rearMasked = rear & mask;
67 uint32_t frontMasked = front & mask;
68 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070069 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070070 }
71 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080072 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070073 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070074 if (lost != NULL) {
75 // TODO provide a more accurate estimate
76 *lost = (genDiff / mFrameCountP2) * mFrameCount;
77 }
78 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070079 }
80 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080081 }
82 }
83 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -070084 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070085 if (lost != NULL) {
86 *lost = diff - mFrameCount;
87 }
88 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070089 }
90 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080091}
92
Glenn Kasten6d7ad762016-06-15 17:05:54 -070093////////////////////////////////////////////////////////////////////////////////
94
Glenn Kasten09acf782016-06-17 10:28:05 -070095audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer)
96 __attribute__((no_sanitize("integer"))) :
97 audio_utils_fifo_base(frameCount), mFrameSize(frameSize), mBuffer(buffer)
98{
99 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
100 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700101 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
102 frameCount > ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700103}
104
105audio_utils_fifo::~audio_utils_fifo()
106{
107}
108
109////////////////////////////////////////////////////////////////////////////////
110
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700111audio_utils_fifo_provider::audio_utils_fifo_provider() :
112 mObtained(0)
113{
114}
115
116audio_utils_fifo_provider::~audio_utils_fifo_provider()
117{
118}
119
120////////////////////////////////////////////////////////////////////////////////
121
122audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
123 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0)
124{
125}
126
127audio_utils_fifo_writer::~audio_utils_fifo_writer()
128{
129}
130
131ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700132 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800133{
Glenn Kasten547a9922016-06-15 13:07:31 -0700134 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700135 ssize_t availToWrite = obtain(iovec, count);
Glenn Kasten547a9922016-06-15 13:07:31 -0700136 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700137 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
138 iovec[0].mLength * mFifo.mFrameSize);
139 if (iovec[1].mLength > 0) {
140 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
141 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
142 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700143 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700144 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700145 }
146 return availToWrite;
147}
148
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700149ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700150 __attribute__((no_sanitize("integer")))
151{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700152 size_t availToWrite;
153 if (mFifo.mThrottleFront != NULL) {
154 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
155 std::memory_order_acquire);
156 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
157 if (filled < 0) {
158 mObtained = 0;
159 return (ssize_t) filled;
160 }
161 availToWrite = (size_t) mFifo.mFrameCount - (size_t) filled;
162 } else {
163 availToWrite = mFifo.mFrameCount;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700164 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800165 if (availToWrite > count) {
166 availToWrite = count;
167 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700168 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
169 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800170 if (part1 > availToWrite) {
171 part1 = availToWrite;
172 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700173 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700174 iovec[0].mOffset = rearMasked;
175 iovec[0].mLength = part1;
176 iovec[1].mOffset = 0;
177 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700178 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800179 return availToWrite;
180}
181
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700182void audio_utils_fifo_writer::release(size_t count)
183 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700184{
185 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700186 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700187 mLocalRear = mFifo.sum(mLocalRear, count);
188 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
Glenn Kasten547a9922016-06-15 13:07:31 -0700189 std::memory_order_release);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700190 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700191 }
192}
193
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700194////////////////////////////////////////////////////////////////////////////////
195
196audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
197 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0)
198{
199 if (throttlesWriter) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700200 LOG_ALWAYS_FATAL_IF(fifo.mThrottleFront != NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700201 fifo.mThrottleFront = &mSharedFront;
202 }
203}
204
205audio_utils_fifo_reader::~audio_utils_fifo_reader()
206{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700207 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kastena7a0e042016-06-17 10:53:09 -0700208 if (mFifo.mThrottleFront == &mSharedFront) {
209 mFifo.mThrottleFront = NULL;
210 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700211}
212
213ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700214 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800215{
Glenn Kasten547a9922016-06-15 13:07:31 -0700216 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700217 ssize_t availToRead = obtain(iovec, count, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700218 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700219 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
220 iovec[0].mLength * mFifo.mFrameSize);
221 if (iovec[1].mLength > 0) {
222 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
223 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
224 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700225 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700226 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700227 }
228 return availToRead;
229}
230
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700231ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700232 __attribute__((no_sanitize("integer")))
233{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700234 return obtain(iovec, count, NULL);
235}
236
237void audio_utils_fifo_reader::release(size_t count)
238 __attribute__((no_sanitize("integer")))
239{
240 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700241 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700242 mLocalFront = mFifo.sum(mLocalFront, count);
243 if (mFifo.mThrottleFront == &mSharedFront) {
244 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
245 std::memory_order_release);
246 }
247 mObtained -= count;
248 }
249}
250
251ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, size_t *lost)
252 __attribute__((no_sanitize("integer")))
253{
254 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
255 std::memory_order_acquire);
256 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700257 if (filled < 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700258 if (filled == android::BAD_INDEX) {
259 mLocalFront = rear;
260 }
261 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700262 return (ssize_t) filled;
263 }
264 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800265 if (availToRead > count) {
266 availToRead = count;
267 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700268 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
269 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800270 if (part1 > availToRead) {
271 part1 = availToRead;
272 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700273 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700274 iovec[0].mOffset = frontMasked;
275 iovec[0].mLength = part1;
276 iovec[1].mOffset = 0;
277 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700278 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700279 return availToRead;
280}