blob: 29c6642c9579946bfdc5bd237b00c29c4a8fda85 [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 Kasten9052f3b2016-07-08 16:24:41 -070020#include <errno.h>
Glenn Kasten0ab1d862016-06-20 12:04:56 -070021#include <limits.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080022#include <stdlib.h>
23#include <string.h>
Glenn Kasten9052f3b2016-07-08 16:24:41 -070024
Glenn Kastenc0924bc2016-10-02 13:00:19 -070025// FIXME futex portion is not supported on macOS, should use the macOS alternative
Glenn Kasten9052f3b2016-07-08 16:24:41 -070026#ifdef __linux__
27#include <linux/futex.h>
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070028#include <sys/syscall.h>
Glenn Kasten9052f3b2016-07-08 16:24:41 -070029#else
30#define FUTEX_WAIT 0
31#define FUTEX_WAIT_PRIVATE 0
32#define FUTEX_WAKE 0
33#define FUTEX_WAKE_PRIVATE 0
34#endif
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070035
Glenn Kasten9b4c8052015-01-06 14:13:13 -080036#include <audio_utils/fifo.h>
37#include <audio_utils/roundup.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080038#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070039#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080040
Glenn Kastenc0924bc2016-10-02 13:00:19 -070041#ifdef __linux__
42#ifdef __ANDROID__
43// bionic for Android provides clock_nanosleep
44#else
45// bionic for desktop Linux omits clock_nanosleep
46int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request,
47 struct timespec *remain)
48{
49 return syscall(SYS_clock_nanosleep, clock_id, flags, request, remain);
50}
51#endif // __ANDROID__
52#else // __linux__
53// macOS doesn't have clock_nanosleep
Glenn Kastenc16f93d2016-10-14 10:05:26 -070054typedef int clockid_t;
55#define CLOCK_MONOTONIC 0
Glenn Kastenc0924bc2016-10-02 13:00:19 -070056int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request,
57 struct timespec *remain)
58{
Glenn Kastenc16f93d2016-10-14 10:05:26 -070059 (void) clock_id;
60 (void) flags;
61 (void) request;
62 (void) remain;
Glenn Kastenc0924bc2016-10-02 13:00:19 -070063 errno = ENOSYS;
64 return -1;
65}
66#endif // __linux__
67
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070068static int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
69{
Glenn Kasten9052f3b2016-07-08 16:24:41 -070070#ifdef __linux__
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070071 return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
Glenn Kastenc0924bc2016-10-02 13:00:19 -070072#else // __linux__
73 // macOS doesn't have futex
Glenn Kasten86c4a6d2016-07-09 10:37:17 -070074 (void) addr1;
75 (void) op;
76 (void) val1;
77 (void) timeout;
78 (void) addr2;
79 (void) val3;
Glenn Kasten9052f3b2016-07-08 16:24:41 -070080 errno = ENOSYS;
81 return -1;
Glenn Kastenc0924bc2016-10-02 13:00:19 -070082#endif // __linux__
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070083}
84
Glenn Kastendc1ff1f2016-09-02 13:54:59 -070085audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
Glenn Kastenc0924bc2016-10-02 13:00:19 -070086 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070087 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070088 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070089 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kastenc0924bc2016-10-02 13:00:19 -070090 // FIXME need an API to configure the sync types
91 mWriterRear(writerRear), mWriterRearSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
92 mThrottleFront(throttleFront), mThrottleFrontSync(AUDIO_UTILS_FIFO_SYNC_SHARED)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080093{
Glenn Kasten09acf782016-06-17 10:28:05 -070094 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten0ab1d862016-06-20 12:04:56 -070095 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080096}
97
Glenn Kasten09acf782016-06-17 10:28:05 -070098audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080099{
100}
101
Glenn Kasten09acf782016-06-17 10:28:05 -0700102uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700103 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800104{
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700105 if (mFudgeFactor) {
106 uint32_t mask = mFrameCountP2 - 1;
107 ALOG_ASSERT((index & mask) < mFrameCount);
108 ALOG_ASSERT(increment <= mFrameCountP2);
109 if ((index & mask) + increment >= mFrameCount) {
110 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800111 }
112 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700113 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800114 return index;
115 } else {
116 return index + increment;
117 }
118}
119
Glenn Kasten09acf782016-06-17 10:28:05 -0700120int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700121 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800122{
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700123 uint32_t diff = rear - front;
124 if (mFudgeFactor) {
125 uint32_t mask = mFrameCountP2 - 1;
126 uint32_t rearMasked = rear & mask;
127 uint32_t frontMasked = front & mask;
128 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700129 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700130 }
131 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800132 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700133 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700134 if (lost != NULL) {
135 // TODO provide a more accurate estimate
136 *lost = (genDiff / mFrameCountP2) * mFrameCount;
137 }
138 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700139 }
140 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800141 }
142 }
143 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700144 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700145 if (lost != NULL) {
146 *lost = diff - mFrameCount;
147 }
148 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700149 }
150 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800151}
152
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700153////////////////////////////////////////////////////////////////////////////////
154
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700155audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700156 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten09acf782016-06-17 10:28:05 -0700157 __attribute__((no_sanitize("integer"))) :
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700158 audio_utils_fifo_base(frameCount, writerRear, throttleFront),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700159 mFrameSize(frameSize), mBuffer(buffer)
Glenn Kasten09acf782016-06-17 10:28:05 -0700160{
161 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
162 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700163 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
164 frameCount > ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700165}
166
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700167audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
168 bool throttlesWriter) :
169 audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
170 throttlesWriter ? &mSingleProcessSharedFront : NULL)
171{
172}
173
Glenn Kasten09acf782016-06-17 10:28:05 -0700174audio_utils_fifo::~audio_utils_fifo()
175{
176}
177
178////////////////////////////////////////////////////////////////////////////////
179
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700180audio_utils_fifo_provider::audio_utils_fifo_provider() :
181 mObtained(0)
182{
183}
184
185audio_utils_fifo_provider::~audio_utils_fifo_provider()
186{
187}
188
189////////////////////////////////////////////////////////////////////////////////
190
191audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700192 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0),
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700193 mLowLevelArm(fifo.mFrameCount), mHighLevelTrigger(0),
194 mArmed(true), // because initial fill level of zero is < mLowLevelArm
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700195 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700196{
197}
198
199audio_utils_fifo_writer::~audio_utils_fifo_writer()
200{
201}
202
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700203ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count, struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700204 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800205{
Glenn Kasten547a9922016-06-15 13:07:31 -0700206 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700207 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700208 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700209 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
210 iovec[0].mLength * mFifo.mFrameSize);
211 if (iovec[1].mLength > 0) {
212 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
213 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
214 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700215 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700216 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700217 }
218 return availToWrite;
219}
220
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700221// iovec == NULL is not part of the public API, but is used internally to mean don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700222ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
223 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700224 __attribute__((no_sanitize("integer")))
225{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700226 int err = 0;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700227 size_t availToWrite;
228 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700229 uint32_t front;
230 for (;;) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700231 front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex, std::memory_order_acquire);
232 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700233 if (filled < 0) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700234 // on error, return an empty slice
235 if (iovec != NULL) {
236 iovec[0].mOffset = 0;
237 iovec[0].mLength = 0;
238 iovec[1].mOffset = 0;
239 iovec[1].mLength = 0;
240 mObtained = 0;
241 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700242 return (ssize_t) filled;
243 }
244 availToWrite = mEffectiveFrames > (uint32_t) filled ?
245 mEffectiveFrames - (uint32_t) filled : 0;
246 // TODO pull out "count == 0"
247 if (count == 0 || availToWrite > 0 || timeout == NULL ||
248 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
249 break;
250 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700251 // TODO add comments
252 // TODO abstract out switch and replace by general sync object
253 int op = FUTEX_WAIT;
254 switch (mFifo.mThrottleFrontSync) {
255 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
256 err = clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout, NULL /*remain*/);
257 if (err < 0) {
258 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
259 err = -errno;
260 } else {
261 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700262 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700263 break;
264 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
265 op = FUTEX_WAIT_PRIVATE;
266 // fall through
267 case AUDIO_UTILS_FIFO_SYNC_SHARED:
268 if (timeout->tv_sec == LONG_MAX) {
269 timeout = NULL;
270 }
271 err = sys_futex(&mFifo.mThrottleFront->mIndex, op, front, timeout, NULL, 0);
272 if (err < 0) {
273 switch (errno) {
274 case EINTR:
275 case ETIMEDOUT:
276 err = -errno;
277 break;
278 default:
279 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
280 break;
281 }
282 }
283 break;
284 default:
285 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
286 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700287 }
288 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700289 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700290 } else {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700291 availToWrite = mEffectiveFrames;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700292 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800293 if (availToWrite > count) {
294 availToWrite = count;
295 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700296 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
297 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800298 if (part1 > availToWrite) {
299 part1 = availToWrite;
300 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700301 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700302 // return slice
303 if (iovec != NULL) {
304 iovec[0].mOffset = rearMasked;
305 iovec[0].mLength = part1;
306 iovec[1].mOffset = 0;
307 iovec[1].mLength = part2;
308 mObtained = availToWrite;
309 }
310 return availToWrite > 0 ? availToWrite : err;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800311}
312
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700313void audio_utils_fifo_writer::release(size_t count)
314 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700315{
316 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700317 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700318 if (mFifo.mThrottleFront != NULL) {
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700319 uint32_t front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700320 std::memory_order_acquire);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700321 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700322 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700323 atomic_store_explicit(&mFifo.mWriterRear.mIndex, mLocalRear,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700324 std::memory_order_release);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700325 // TODO add comments
326 int op = FUTEX_WAKE;
327 switch (mFifo.mWriterRearSync) {
328 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
329 break;
330 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
331 op = FUTEX_WAKE_PRIVATE;
332 // fall through
333 case AUDIO_UTILS_FIFO_SYNC_SHARED:
334 if (filled >= 0) {
335 if ((uint32_t) filled < mLowLevelArm) {
336 mArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700337 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700338 if (mArmed && filled + count > mHighLevelTrigger) {
339 int err = sys_futex(&mFifo.mWriterRear.mIndex,
340 op, INT_MAX /*waiters*/, NULL, NULL, 0);
341 // err is number of processes woken up
342 if (err < 0) {
343 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
344 __func__, err, errno);
345 }
346 mArmed = false;
347 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700348 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700349 break;
350 default:
351 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
352 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700353 }
354 } else {
355 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700356 atomic_store_explicit(&mFifo.mWriterRear.mIndex, mLocalRear,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700357 std::memory_order_release);
358 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700359 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700360 }
361}
362
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700363ssize_t audio_utils_fifo_writer::available()
364{
365 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
366}
367
368void audio_utils_fifo_writer::resize(uint32_t frameCount)
369{
370 // cap to range [0, mFifo.mFrameCount]
371 if (frameCount > mFifo.mFrameCount) {
372 frameCount = mFifo.mFrameCount;
373 }
374 // if we reduce the effective frame count, update hysteresis points to be within the new range
375 if (frameCount < mEffectiveFrames) {
376 if (mLowLevelArm > frameCount) {
377 mLowLevelArm = frameCount;
378 }
379 if (mHighLevelTrigger > frameCount) {
380 mHighLevelTrigger = frameCount;
381 }
382 }
383 mEffectiveFrames = frameCount;
384}
385
386uint32_t audio_utils_fifo_writer::getSize() const
387{
388 return mEffectiveFrames;
389}
390
391void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
392{
393 // cap to range [0, mEffectiveFrames]
394 if (lowLevelArm > mEffectiveFrames) {
395 lowLevelArm = mEffectiveFrames;
396 }
397 if (highLevelTrigger > mEffectiveFrames) {
398 highLevelTrigger = mEffectiveFrames;
399 }
400 // TODO this is overly conservative; it would be better to arm based on actual fill level
401 if (lowLevelArm > mLowLevelArm) {
402 mArmed = true;
403 }
404 mLowLevelArm = lowLevelArm;
405 mHighLevelTrigger = highLevelTrigger;
406}
407
408void audio_utils_fifo_writer::getHysteresis(uint32_t *lowLevelArm, uint32_t *highLevelTrigger) const
409{
410 *lowLevelArm = mLowLevelArm;
411 *highLevelTrigger = mHighLevelTrigger;
412}
413
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700414////////////////////////////////////////////////////////////////////////////////
415
416audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700417 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0),
418 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700419 mHighLevelArm(-1), mLowLevelTrigger(mFifo.mFrameCount),
420 mArmed(true) // because initial fill level of zero is > mHighLevelArm
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700421{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700422}
423
424audio_utils_fifo_reader::~audio_utils_fifo_reader()
425{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700426 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700427}
428
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700429ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, struct timespec *timeout,
430 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700431 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800432{
Glenn Kasten547a9922016-06-15 13:07:31 -0700433 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700434 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700435 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700436 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
437 iovec[0].mLength * mFifo.mFrameSize);
438 if (iovec[1].mLength > 0) {
439 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
440 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
441 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700442 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700443 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700444 }
445 return availToRead;
446}
447
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700448ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
449 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700450 __attribute__((no_sanitize("integer")))
451{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700452 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700453}
454
455void audio_utils_fifo_reader::release(size_t count)
456 __attribute__((no_sanitize("integer")))
457{
458 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700459 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700460 if (mThrottleFront != NULL) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700461 uint32_t rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700462 std::memory_order_acquire);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700463 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700464 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700465 atomic_store_explicit(&mThrottleFront->mIndex, mLocalFront,
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700466 std::memory_order_release);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700467 // TODO add comments
468 int op = FUTEX_WAKE;
469 switch (mFifo.mThrottleFrontSync) {
470 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
471 break;
472 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
473 op = FUTEX_WAKE_PRIVATE;
474 // fall through
475 case AUDIO_UTILS_FIFO_SYNC_SHARED:
476 if (filled >= 0) {
477 if (filled > mHighLevelArm) {
478 mArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700479 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700480 if (mArmed && filled - count < mLowLevelTrigger) {
481 int err = sys_futex(&mThrottleFront->mIndex,
482 op, 1 /*waiters*/, NULL, NULL, 0);
483 // err is number of processes woken up
484 if (err < 0 || err > 1) {
485 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
486 __func__, err, errno);
487 }
488 mArmed = false;
489 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700490 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700491 break;
492 default:
493 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
494 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700495 }
496 } else {
497 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700498 }
499 mObtained -= count;
500 }
501}
502
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700503// iovec == NULL is not part of the public API, but is used internally to mean don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700504ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
505 struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700506 __attribute__((no_sanitize("integer")))
507{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700508 int err = 0;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700509 uint32_t rear;
510 for (;;) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700511 rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700512 std::memory_order_acquire);
513 // TODO pull out "count == 0"
514 if (count == 0 || rear != mLocalFront || timeout == NULL ||
515 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
516 break;
517 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700518 // TODO add comments
519 int op = FUTEX_WAIT;
520 switch (mFifo.mWriterRearSync) {
521 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
522 err = clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout, NULL /*remain*/);
523 if (err < 0) {
524 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
525 err = -errno;
526 } else {
527 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700528 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700529 break;
530 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
531 op = FUTEX_WAIT_PRIVATE;
532 // fall through
533 case AUDIO_UTILS_FIFO_SYNC_SHARED:
534 if (timeout->tv_sec == LONG_MAX) {
535 timeout = NULL;
536 }
537 err = sys_futex(&mFifo.mWriterRear.mIndex, op, rear, timeout, NULL, 0);
538 if (err < 0) {
539 switch (errno) {
540 case EINTR:
541 case ETIMEDOUT:
542 err = -errno;
543 break;
544 default:
545 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
546 break;
547 }
548 }
549 break;
550 default:
551 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
552 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700553 }
554 timeout = NULL;
555 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700556 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700557 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700558 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700559 mLocalFront = rear;
560 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700561 // on error, return an empty slice
562 if (iovec != NULL) {
563 iovec[0].mOffset = 0;
564 iovec[0].mLength = 0;
565 iovec[1].mOffset = 0;
566 iovec[1].mLength = 0;
567 mObtained = 0;
568 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700569 return (ssize_t) filled;
570 }
571 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800572 if (availToRead > count) {
573 availToRead = count;
574 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700575 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
576 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800577 if (part1 > availToRead) {
578 part1 = availToRead;
579 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700580 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700581 // return slice
582 if (iovec != NULL) {
583 iovec[0].mOffset = frontMasked;
584 iovec[0].mLength = part1;
585 iovec[1].mOffset = 0;
586 iovec[1].mLength = part2;
587 mObtained = availToRead;
588 }
589 return availToRead > 0 ? availToRead : err;
590}
591
592ssize_t audio_utils_fifo_reader::available()
593{
594 return available(NULL /*lost*/);
595}
596
597ssize_t audio_utils_fifo_reader::available(size_t *lost)
598{
599 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
600}
601
602void audio_utils_fifo_reader::setHysteresis(int32_t highLevelArm, uint32_t lowLevelTrigger)
603{
604 // cap to range [0, mFifo.mFrameCount]
605 if (highLevelArm < 0) {
606 highLevelArm = -1;
607 } else if ((uint32_t) highLevelArm > mFifo.mFrameCount) {
608 highLevelArm = mFifo.mFrameCount;
609 }
610 if (lowLevelTrigger > mFifo.mFrameCount) {
611 lowLevelTrigger = mFifo.mFrameCount;
612 }
613 // TODO this is overly conservative; it would be better to arm based on actual fill level
614 if (highLevelArm < mHighLevelArm) {
615 mArmed = true;
616 }
617 mHighLevelArm = highLevelArm;
618 mLowLevelTrigger = lowLevelTrigger;
619}
620
621void audio_utils_fifo_reader::getHysteresis(int32_t *highLevelArm, uint32_t *lowLevelTrigger) const
622{
623 *highLevelArm = mHighLevelArm;
624 *lowLevelTrigger = mLowLevelTrigger;
Glenn Kasten547a9922016-06-15 13:07:31 -0700625}