blob: 827b441b3e9a8b39b5866075378ec6ada1c9ee44 [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 Kasten6d7ad762016-06-15 17:05:54 -070027audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer)
28 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070029 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
30 mFudgeFactor(mFrameCountP2 - mFrameCount), mFrameSize(frameSize), mBuffer(buffer),
Glenn Kasten6d7ad762016-06-15 17:05:54 -070031 mSharedRear(0), mThrottleFront(NULL)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080032{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070033 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
34 // be able to distinguish successful and error return values from read and write.
35 ALOG_ASSERT(frameCount > 0 && frameSize > 0 && buffer != NULL &&
36 frameCount <= ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080037}
38
Glenn Kasten9b4fe472016-06-13 09:34:57 -070039audio_utils_fifo::~audio_utils_fifo()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080040{
41}
42
Glenn Kasten9b4fe472016-06-13 09:34:57 -070043uint32_t audio_utils_fifo::sum(uint32_t index, uint32_t increment)
44 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080045{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070046 if (mFudgeFactor) {
47 uint32_t mask = mFrameCountP2 - 1;
48 ALOG_ASSERT((index & mask) < mFrameCount);
49 ALOG_ASSERT(increment <= mFrameCountP2);
50 if ((index & mask) + increment >= mFrameCount) {
51 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080052 }
53 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070054 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080055 return index;
56 } else {
57 return index + increment;
58 }
59}
60
Glenn Kasten6d7ad762016-06-15 17:05:54 -070061int32_t audio_utils_fifo::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070062 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080063{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070064 uint32_t diff = rear - front;
65 if (mFudgeFactor) {
66 uint32_t mask = mFrameCountP2 - 1;
67 uint32_t rearMasked = rear & mask;
68 uint32_t frontMasked = front & mask;
69 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070070 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070071 }
72 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080073 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070074 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070075 if (lost != NULL) {
76 // TODO provide a more accurate estimate
77 *lost = (genDiff / mFrameCountP2) * mFrameCount;
78 }
79 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070080 }
81 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080082 }
83 }
84 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -070085 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070086 if (lost != NULL) {
87 *lost = diff - mFrameCount;
88 }
89 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070090 }
91 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080092}
93
Glenn Kasten6d7ad762016-06-15 17:05:54 -070094////////////////////////////////////////////////////////////////////////////////
95
96audio_utils_fifo_provider::audio_utils_fifo_provider() :
97 mObtained(0)
98{
99}
100
101audio_utils_fifo_provider::~audio_utils_fifo_provider()
102{
103}
104
105////////////////////////////////////////////////////////////////////////////////
106
107audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
108 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0)
109{
110}
111
112audio_utils_fifo_writer::~audio_utils_fifo_writer()
113{
114}
115
116ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700117 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800118{
Glenn Kasten547a9922016-06-15 13:07:31 -0700119 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700120 ssize_t availToWrite = obtain(iovec, count);
Glenn Kasten547a9922016-06-15 13:07:31 -0700121 if (availToWrite > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700122 memcpy(iovec[0].mBase, buffer, iovec[0].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700123 if (iovec[1].mLen > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700124 memcpy(iovec[1].mBase, (char *) buffer + (iovec[0].mLen * mFifo.mFrameSize),
125 iovec[1].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700126 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700127 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700128 }
129 return availToWrite;
130}
131
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700132ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700133 __attribute__((no_sanitize("integer")))
134{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700135 size_t availToWrite;
136 if (mFifo.mThrottleFront != NULL) {
137 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
138 std::memory_order_acquire);
139 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
140 if (filled < 0) {
141 mObtained = 0;
142 return (ssize_t) filled;
143 }
144 availToWrite = (size_t) mFifo.mFrameCount - (size_t) filled;
145 } else {
146 availToWrite = mFifo.mFrameCount;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700147 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800148 if (availToWrite > count) {
149 availToWrite = count;
150 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700151 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
152 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800153 if (part1 > availToWrite) {
154 part1 = availToWrite;
155 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700156 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
157 iovec[0].mLen = part1;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700158 iovec[0].mBase = part1 > 0 ? (char *) mFifo.mBuffer + (rearMasked * mFifo.mFrameSize) : NULL;
Glenn Kasten547a9922016-06-15 13:07:31 -0700159 iovec[1].mLen = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700160 iovec[1].mBase = part2 > 0 ? mFifo.mBuffer : NULL;
161 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800162 return availToWrite;
163}
164
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700165void audio_utils_fifo_writer::release(size_t count)
166 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700167{
168 if (count > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700169 ALOG_ASSERT(count <= mObtained);
170 mLocalRear = mFifo.sum(mLocalRear, count);
171 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
Glenn Kasten547a9922016-06-15 13:07:31 -0700172 std::memory_order_release);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700173 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700174 }
175}
176
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700177////////////////////////////////////////////////////////////////////////////////
178
179audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
180 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0)
181{
182 if (throttlesWriter) {
183 fifo.mThrottleFront = &mSharedFront;
184 }
185}
186
187audio_utils_fifo_reader::~audio_utils_fifo_reader()
188{
189}
190
191ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700192 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800193{
Glenn Kasten547a9922016-06-15 13:07:31 -0700194 audio_utils_iovec iovec[2];
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700195 ssize_t availToRead = obtain(iovec, count, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700196 if (availToRead > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700197 memcpy(buffer, iovec[0].mBase, iovec[0].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700198 if (iovec[1].mLen > 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700199 memcpy((char *) buffer + (iovec[0].mLen * mFifo.mFrameSize), iovec[1].mBase,
200 iovec[1].mLen * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700201 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700202 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700203 }
204 return availToRead;
205}
206
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700207ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count)
Glenn Kasten547a9922016-06-15 13:07:31 -0700208 __attribute__((no_sanitize("integer")))
209{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700210 return obtain(iovec, count, NULL);
211}
212
213void audio_utils_fifo_reader::release(size_t count)
214 __attribute__((no_sanitize("integer")))
215{
216 if (count > 0) {
217 ALOG_ASSERT(count <= mObtained);
218 mLocalFront = mFifo.sum(mLocalFront, count);
219 if (mFifo.mThrottleFront == &mSharedFront) {
220 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
221 std::memory_order_release);
222 }
223 mObtained -= count;
224 }
225}
226
227ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, size_t *lost)
228 __attribute__((no_sanitize("integer")))
229{
230 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
231 std::memory_order_acquire);
232 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700233 if (filled < 0) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700234 if (filled == android::BAD_INDEX) {
235 mLocalFront = rear;
236 }
237 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700238 return (ssize_t) filled;
239 }
240 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800241 if (availToRead > count) {
242 availToRead = count;
243 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700244 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
245 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800246 if (part1 > availToRead) {
247 part1 = availToRead;
248 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700249 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
250 iovec[0].mLen = part1;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700251 iovec[0].mBase = part1 > 0 ? (char *) mFifo.mBuffer + (frontMasked * mFifo.mFrameSize) : NULL;
Glenn Kasten547a9922016-06-15 13:07:31 -0700252 iovec[1].mLen = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700253 iovec[1].mBase = part2 > 0 ? mFifo.mBuffer : NULL;
254 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700255 return availToRead;
256}