fifo.cpp revision c0924bc38334c7adbf8cbc9cfa9d00559c002652
19b4c805bc22842480690f14826b729845887963aGlenn Kasten/*
29b4c805bc22842480690f14826b729845887963aGlenn Kasten * Copyright (C) 2015 The Android Open Source Project
39b4c805bc22842480690f14826b729845887963aGlenn Kasten *
49b4c805bc22842480690f14826b729845887963aGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
59b4c805bc22842480690f14826b729845887963aGlenn Kasten * you may not use this file except in compliance with the License.
69b4c805bc22842480690f14826b729845887963aGlenn Kasten * You may obtain a copy of the License at
79b4c805bc22842480690f14826b729845887963aGlenn Kasten *
89b4c805bc22842480690f14826b729845887963aGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
99b4c805bc22842480690f14826b729845887963aGlenn Kasten *
109b4c805bc22842480690f14826b729845887963aGlenn Kasten * Unless required by applicable law or agreed to in writing, software
119b4c805bc22842480690f14826b729845887963aGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
129b4c805bc22842480690f14826b729845887963aGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139b4c805bc22842480690f14826b729845887963aGlenn Kasten * See the License for the specific language governing permissions and
149b4c805bc22842480690f14826b729845887963aGlenn Kasten * limitations under the License.
159b4c805bc22842480690f14826b729845887963aGlenn Kasten */
169b4c805bc22842480690f14826b729845887963aGlenn Kasten
179b4c805bc22842480690f14826b729845887963aGlenn Kasten//#define LOG_NDEBUG 0
189b4c805bc22842480690f14826b729845887963aGlenn Kasten#define LOG_TAG "audio_utils_fifo"
199b4c805bc22842480690f14826b729845887963aGlenn Kasten
209052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#include <errno.h>
210ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten#include <limits.h>
229b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <stdlib.h>
239b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <string.h>
249052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten
25c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten// FIXME futex portion is not supported on macOS, should use the macOS alternative
269052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#ifdef __linux__
279052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#include <linux/futex.h>
283ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten#include <sys/syscall.h>
299052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#else
309052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#define FUTEX_WAIT 0
319052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#define FUTEX_WAIT_PRIVATE 0
329052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#define FUTEX_WAKE 0
339052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#define FUTEX_WAKE_PRIVATE 0
349052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#endif
353ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten
369b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <audio_utils/fifo.h>
379b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <audio_utils/roundup.h>
389b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <cutils/log.h>
399b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten#include <utils/Errors.h>
409b4c805bc22842480690f14826b729845887963aGlenn Kasten
41c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#ifdef __linux__
42c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#ifdef __ANDROID__
43c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten// bionic for Android provides clock_nanosleep
44c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#else
45c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten// bionic for desktop Linux omits clock_nanosleep
46c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenint clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request,
47c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        struct timespec *remain)
48c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
49c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return syscall(SYS_clock_nanosleep, clock_id, flags, request, remain);
50c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
51c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#endif  // __ANDROID__
52c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#else   // __linux__
53c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten// macOS doesn't have clock_nanosleep
54c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenint clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request,
55c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        struct timespec *remain)
56c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
57c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    errno = ENOSYS;
58c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return -1;
59c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
60c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#endif  // __linux__
61c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
623ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenstatic int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
633ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten{
649052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten#ifdef __linux__
653ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
66c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#else   // __linux__
67c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // macOS doesn't have futex
6886c4a6da76eb80896349703c4d4bb928722e0110Glenn Kasten    (void) addr1;
6986c4a6da76eb80896349703c4d4bb928722e0110Glenn Kasten    (void) op;
7086c4a6da76eb80896349703c4d4bb928722e0110Glenn Kasten    (void) val1;
7186c4a6da76eb80896349703c4d4bb928722e0110Glenn Kasten    (void) timeout;
7286c4a6da76eb80896349703c4d4bb928722e0110Glenn Kasten    (void) addr2;
7386c4a6da76eb80896349703c4d4bb928722e0110Glenn Kasten    (void) val3;
749052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten    errno = ENOSYS;
759052f3b550e82b0dc6ea83f9cbe37e5a0b6f2573Glenn Kasten    return -1;
76c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten#endif  // __linux__
773ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten}
783ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten
79dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
80c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
816d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer"))) :
829b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
8309acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    mFudgeFactor(mFrameCountP2 - mFrameCount),
84c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // FIXME need an API to configure the sync types
85c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mWriterRear(writerRear), mWriterRearSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
86c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mThrottleFront(throttleFront), mThrottleFrontSync(AUDIO_UTILS_FIFO_SYNC_SHARED)
879b4c805bc22842480690f14826b729845887963aGlenn Kasten{
8809acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    // actual upper bound on frameCount will depend on the frame size
890ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT_MAX));
909b4c805bc22842480690f14826b729845887963aGlenn Kasten}
919b4c805bc22842480690f14826b729845887963aGlenn Kasten
9209acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenaudio_utils_fifo_base::~audio_utils_fifo_base()
939b4c805bc22842480690f14826b729845887963aGlenn Kasten{
949b4c805bc22842480690f14826b729845887963aGlenn Kasten}
959b4c805bc22842480690f14826b729845887963aGlenn Kasten
9609acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenuint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
979b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
989b4c805bc22842480690f14826b729845887963aGlenn Kasten{
999b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (mFudgeFactor) {
1009b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t mask = mFrameCountP2 - 1;
1019b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT((index & mask) < mFrameCount);
1029b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT(increment <= mFrameCountP2);
1039b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        if ((index & mask) + increment >= mFrameCount) {
1049b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            increment += mFudgeFactor;
1059b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
1069b4c805bc22842480690f14826b729845887963aGlenn Kasten        index += increment;
1079b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT((index & mask) < mFrameCount);
1089b4c805bc22842480690f14826b729845887963aGlenn Kasten        return index;
1099b4c805bc22842480690f14826b729845887963aGlenn Kasten    } else {
1109b4c805bc22842480690f14826b729845887963aGlenn Kasten        return index + increment;
1119b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1129b4c805bc22842480690f14826b729845887963aGlenn Kasten}
1139b4c805bc22842480690f14826b729845887963aGlenn Kasten
11409acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenint32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
1159b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
1169b4c805bc22842480690f14826b729845887963aGlenn Kasten{
1179b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t diff = rear - front;
1189b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (mFudgeFactor) {
1199b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t mask = mFrameCountP2 - 1;
1209b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t rearMasked = rear & mask;
1219b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t frontMasked = front & mask;
1229b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
1236d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten            return -EIO;
1249b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        }
1259b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t genDiff = (rear & ~mask) - (front & ~mask);
1269b4c805bc22842480690f14826b729845887963aGlenn Kasten        if (genDiff != 0) {
1279b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            if (genDiff > mFrameCountP2) {
1286d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                if (lost != NULL) {
1296d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                    // TODO provide a more accurate estimate
1306d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                    *lost = (genDiff / mFrameCountP2) * mFrameCount;
1316d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                }
1326d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                return -EOVERFLOW;
1339b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            }
1349b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            diff -= mFudgeFactor;
1359b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
1369b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1379b4c805bc22842480690f14826b729845887963aGlenn Kasten    // FIFO should not be overfull
1389b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (diff > mFrameCount) {
1396d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        if (lost != NULL) {
1406d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten            *lost = diff - mFrameCount;
1416d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
1426d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        return -EOVERFLOW;
1439b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
1449b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    return (int32_t) diff;
1459b4c805bc22842480690f14826b729845887963aGlenn Kasten}
1469b4c805bc22842480690f14826b729845887963aGlenn Kasten
1476d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
1486d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
149dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
150c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
15109acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten        __attribute__((no_sanitize("integer"))) :
152c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    audio_utils_fifo_base(frameCount, writerRear, throttleFront),
153dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    mFrameSize(frameSize), mBuffer(buffer)
15409acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten{
15509acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
15609acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    // be able to distinguish successful and error return values from read and write.
1570ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
1580ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten            frameCount > ((uint32_t) INT_MAX) / frameSize);
15909acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten}
16009acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
161dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
162dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        bool throttlesWriter) :
163dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
164dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        throttlesWriter ?  &mSingleProcessSharedFront : NULL)
165dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten{
166dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten}
167dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten
16809acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenaudio_utils_fifo::~audio_utils_fifo()
16909acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten{
17009acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten}
17109acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
17209acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten////////////////////////////////////////////////////////////////////////////////
17309acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
1746d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_provider::audio_utils_fifo_provider() :
1756d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    mObtained(0)
1766d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1776d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1786d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1796d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_provider::~audio_utils_fifo_provider()
1806d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1816d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1826d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1836d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
1846d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1856d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
1863ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0),
187c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mLowLevelArm(fifo.mFrameCount), mHighLevelTrigger(0),
188c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mArmed(true),   // because initial fill level of zero is < mLowLevelArm
1893ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    mEffectiveFrames(fifo.mFrameCount)
1906d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1916d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1926d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1936d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_writer::~audio_utils_fifo_writer()
1946d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1956d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1966d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1973ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count, struct timespec *timeout)
1989b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
1999b4c805bc22842480690f14826b729845887963aGlenn Kasten{
200547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
2013ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    ssize_t availToWrite = obtain(iovec, count, timeout);
202547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToWrite > 0) {
203169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
204169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                iovec[0].mLength * mFifo.mFrameSize);
205169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        if (iovec[1].mLength > 0) {
206169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten            memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
207169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
208169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    iovec[1].mLength * mFifo.mFrameSize);
209547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
2106d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        release(availToWrite);
211547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
212547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToWrite;
213547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
214547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
215c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten// iovec == NULL is not part of the public API, but is used internally to mean don't set mObtained
2163ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
2173ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        struct timespec *timeout)
218547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
219547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
220c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    int err = 0;
2216d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    size_t availToWrite;
2226d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    if (mFifo.mThrottleFront != NULL) {
2233ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        uint32_t front;
2243ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        for (;;) {
225c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex, std::memory_order_acquire);
226c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(mLocalRear, front);
2273ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            if (filled < 0) {
228c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // on error, return an empty slice
229c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (iovec != NULL) {
230c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    iovec[0].mOffset = 0;
231c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    iovec[0].mLength = 0;
232c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    iovec[1].mOffset = 0;
233c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    iovec[1].mLength = 0;
234c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    mObtained = 0;
235c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
2363ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                return (ssize_t) filled;
2373ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
2383ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            availToWrite = mEffectiveFrames > (uint32_t) filled ?
2393ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    mEffectiveFrames - (uint32_t) filled : 0;
2403ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            // TODO pull out "count == 0"
2413ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            if (count == 0 || availToWrite > 0 || timeout == NULL ||
2423ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
2433ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                break;
2443ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
245c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
246c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO abstract out switch and replace by general sync object
247c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAIT;
248c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mThrottleFrontSync) {
249c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
250c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout, NULL /*remain*/);
251c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (err < 0) {
252c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
253c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -errno;
254c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                } else {
255c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -ETIMEDOUT;
256c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
257c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
258c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
259c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAIT_PRIVATE;
260c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
261c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
262c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (timeout->tv_sec == LONG_MAX) {
263c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    timeout = NULL;
264c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
265c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = sys_futex(&mFifo.mThrottleFront->mIndex, op, front, timeout, NULL, 0);
266c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (err < 0) {
267c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    switch (errno) {
268c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    case EINTR:
269c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    case ETIMEDOUT:
270c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        err = -errno;
271c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        break;
272c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    default:
273c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
274c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        break;
275c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
2763ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
277c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
278c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
279c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
280c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
2813ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
2823ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            timeout = NULL;
2836d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
2846d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    } else {
2853ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        availToWrite = mEffectiveFrames;
2869b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
2879b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToWrite > count) {
2889b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToWrite = count;
2899b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
2906d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
2916d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    size_t part1 = mFifo.mFrameCount - rearMasked;
2929b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToWrite) {
2939b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToWrite;
2949b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
295547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
296c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // return slice
297c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (iovec != NULL) {
298c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mOffset = rearMasked;
299c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mLength = part1;
300c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mOffset = 0;
301c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mLength = part2;
302c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mObtained = availToWrite;
303c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
304c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return availToWrite > 0 ? availToWrite : err;
305547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
306547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
3076d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenvoid audio_utils_fifo_writer::release(size_t count)
3086d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
309547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
310547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (count > 0) {
3110ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten        LOG_ALWAYS_FATAL_IF(count > mObtained);
3123ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (mFifo.mThrottleFront != NULL) {
313dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten            uint32_t front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex,
3143ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    std::memory_order_acquire);
315c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(mLocalRear, front);
3163ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalRear = mFifo.sum(mLocalRear, count);
317c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            atomic_store_explicit(&mFifo.mWriterRear.mIndex, mLocalRear,
3183ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    std::memory_order_release);
319c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
320c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAKE;
321c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mWriterRearSync) {
322c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
323c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
324c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
325c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAKE_PRIVATE;
326c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
327c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
328c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (filled >= 0) {
329c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    if ((uint32_t) filled < mLowLevelArm) {
330c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        mArmed = true;
331c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
332c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    if (mArmed && filled + count > mHighLevelTrigger) {
333c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        int err = sys_futex(&mFifo.mWriterRear.mIndex,
334c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                op, INT_MAX /*waiters*/, NULL, NULL, 0);
335c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        // err is number of processes woken up
336c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        if (err < 0) {
337c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                            LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
338c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                    __func__, err, errno);
339c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        }
340c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        mArmed = false;
3413ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    }
3423ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
343c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
344c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
345c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
346c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
3473ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
3483ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        } else {
3493ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalRear = mFifo.sum(mLocalRear, count);
350c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            atomic_store_explicit(&mFifo.mWriterRear.mIndex, mLocalRear,
3513ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    std::memory_order_release);
3523ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
3536d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        mObtained -= count;
3546d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    }
3556d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
3566d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
357c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_writer::available()
358c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
359c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
360c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
361c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
362c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::resize(uint32_t frameCount)
363c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
364c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mFifo.mFrameCount]
365c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (frameCount > mFifo.mFrameCount) {
366c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        frameCount = mFifo.mFrameCount;
367c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
368c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // if we reduce the effective frame count, update hysteresis points to be within the new range
369c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (frameCount < mEffectiveFrames) {
370c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        if (mLowLevelArm > frameCount) {
371c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            mLowLevelArm = frameCount;
372c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
373c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        if (mHighLevelTrigger > frameCount) {
374c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            mHighLevelTrigger = frameCount;
375c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
376c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
377c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mEffectiveFrames = frameCount;
378c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
379c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
380c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenuint32_t audio_utils_fifo_writer::getSize() const
381c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
382c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return mEffectiveFrames;
383c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
384c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
385c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
386c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
387c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mEffectiveFrames]
388c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (lowLevelArm > mEffectiveFrames) {
389c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        lowLevelArm = mEffectiveFrames;
390c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
391c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (highLevelTrigger > mEffectiveFrames) {
392c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        highLevelTrigger = mEffectiveFrames;
393c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
394c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // TODO this is overly conservative; it would be better to arm based on actual fill level
395c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (lowLevelArm > mLowLevelArm) {
396c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mArmed = true;
397c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
398c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mLowLevelArm = lowLevelArm;
399c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mHighLevelTrigger = highLevelTrigger;
400c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
401c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
402c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::getHysteresis(uint32_t *lowLevelArm, uint32_t *highLevelTrigger) const
403c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
404c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    *lowLevelArm = mLowLevelArm;
405c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    *highLevelTrigger = mHighLevelTrigger;
406c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
407c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
4086d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
4096d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
4106d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
411dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0),
412dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
413c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mHighLevelArm(-1), mLowLevelTrigger(mFifo.mFrameCount),
414c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mArmed(true)    // because initial fill level of zero is > mHighLevelArm
4156d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
4169b4c805bc22842480690f14826b729845887963aGlenn Kasten}
4179b4c805bc22842480690f14826b729845887963aGlenn Kasten
4186d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_reader::~audio_utils_fifo_reader()
4196d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
4200ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
4216d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4226d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
4233ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, struct timespec *timeout,
4243ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        size_t *lost)
4259b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
4269b4c805bc22842480690f14826b729845887963aGlenn Kasten{
427547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
4283ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    ssize_t availToRead = obtain(iovec, count, timeout, lost);
429547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToRead > 0) {
430169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
431169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                iovec[0].mLength * mFifo.mFrameSize);
432169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        if (iovec[1].mLength > 0) {
433169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten            memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
434169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
435169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    iovec[1].mLength * mFifo.mFrameSize);
436547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
4376d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        release(availToRead);
438547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
439547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToRead;
440547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
441547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
4423ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
4433ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        struct timespec *timeout)
4446d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
4456d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
446c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(iovec, count, timeout, NULL /*lost*/);
4476d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4486d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
4496d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenvoid audio_utils_fifo_reader::release(size_t count)
450547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
451547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
4526d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    if (count > 0) {
4530ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten        LOG_ALWAYS_FATAL_IF(count > mObtained);
454dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        if (mThrottleFront != NULL) {
455c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            uint32_t rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
4563ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    std::memory_order_acquire);
457c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(rear, mLocalFront);
4583ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalFront = mFifo.sum(mLocalFront, count);
459dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten            atomic_store_explicit(&mThrottleFront->mIndex, mLocalFront,
4606d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                    std::memory_order_release);
461c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
462c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAKE;
463c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mThrottleFrontSync) {
464c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
465c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
466c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
467c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAKE_PRIVATE;
468c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
469c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
470c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (filled >= 0) {
471c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    if (filled > mHighLevelArm) {
472c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        mArmed = true;
473c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
474c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    if (mArmed && filled - count < mLowLevelTrigger) {
475c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        int err = sys_futex(&mThrottleFront->mIndex,
476c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                op, 1 /*waiters*/, NULL, NULL, 0);
477c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        // err is number of processes woken up
478c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        if (err < 0 || err > 1) {
479c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                            LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
480c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                    __func__, err, errno);
481c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        }
482c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        mArmed = false;
4833ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    }
4843ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
485c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
486c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
487c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
488c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
4893ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
4903ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        } else {
4913ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalFront = mFifo.sum(mLocalFront, count);
4926d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
4936d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        mObtained -= count;
4946d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    }
4956d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4966d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
497c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten// iovec == NULL is not part of the public API, but is used internally to mean don't set mObtained
4983ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
4993ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        struct timespec *timeout, size_t *lost)
5006d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
5016d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
502c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    int err = 0;
5033ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    uint32_t rear;
5043ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    for (;;) {
505c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
5063ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                std::memory_order_acquire);
5073ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        // TODO pull out "count == 0"
5083ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (count == 0 || rear != mLocalFront || timeout == NULL ||
5093ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
5103ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            break;
5113ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
512c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        // TODO add comments
513c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        int op = FUTEX_WAIT;
514c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        switch (mFifo.mWriterRearSync) {
515c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_SLEEP:
516c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            err = clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout, NULL /*remain*/);
517c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (err < 0) {
518c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
519c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = -errno;
520c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            } else {
521c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = -ETIMEDOUT;
522c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            }
523c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
524c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
525c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            op = FUTEX_WAIT_PRIVATE;
526c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // fall through
527c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_SHARED:
528c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (timeout->tv_sec == LONG_MAX) {
529c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                timeout = NULL;
530c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            }
531c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            err = sys_futex(&mFifo.mWriterRear.mIndex, op, rear, timeout, NULL, 0);
532c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (err < 0) {
533c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                switch (errno) {
534c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                case EINTR:
535c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                case ETIMEDOUT:
536c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -errno;
537c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    break;
538c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                default:
539c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
540c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    break;
541c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
5423ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
543c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
544c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        default:
545c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
546c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
5473ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
5483ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        timeout = NULL;
5493ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    }
5506d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    int32_t filled = mFifo.diff(rear, mLocalFront, lost);
5519b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (filled < 0) {
5523ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (filled == -EOVERFLOW) {
5536d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten            mLocalFront = rear;
5546d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
555c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        // on error, return an empty slice
556c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        if (iovec != NULL) {
557c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            iovec[0].mOffset = 0;
558c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            iovec[0].mLength = 0;
559c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            iovec[1].mOffset = 0;
560c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            iovec[1].mLength = 0;
561c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            mObtained = 0;
562c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
5639b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        return (ssize_t) filled;
5649b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
5659b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t availToRead = (size_t) filled;
5669b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToRead > count) {
5679b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToRead = count;
5689b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
5696d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
5706d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    size_t part1 = mFifo.mFrameCount - frontMasked;
5719b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToRead) {
5729b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToRead;
5739b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
574547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToRead - part1 : 0;
575c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // return slice
576c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (iovec != NULL) {
577c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mOffset = frontMasked;
578c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mLength = part1;
579c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mOffset = 0;
580c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mLength = part2;
581c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mObtained = availToRead;
582c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
583c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return availToRead > 0 ? availToRead : err;
584c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
585c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
586c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_reader::available()
587c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
588c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return available(NULL /*lost*/);
589c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
590c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
591c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_reader::available(size_t *lost)
592c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
593c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
594c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
595c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
596c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_reader::setHysteresis(int32_t highLevelArm, uint32_t lowLevelTrigger)
597c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
598c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mFifo.mFrameCount]
599c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (highLevelArm < 0) {
600c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        highLevelArm = -1;
601c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    } else if ((uint32_t) highLevelArm > mFifo.mFrameCount) {
602c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        highLevelArm = mFifo.mFrameCount;
603c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
604c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (lowLevelTrigger > mFifo.mFrameCount) {
605c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        lowLevelTrigger = mFifo.mFrameCount;
606c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
607c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // TODO this is overly conservative; it would be better to arm based on actual fill level
608c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (highLevelArm < mHighLevelArm) {
609c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mArmed = true;
610c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
611c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mHighLevelArm = highLevelArm;
612c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mLowLevelTrigger = lowLevelTrigger;
613c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
614c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
615c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_reader::getHysteresis(int32_t *highLevelArm, uint32_t *lowLevelTrigger) const
616c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
617c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    *highLevelArm = mHighLevelArm;
618c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    *lowLevelTrigger = mLowLevelTrigger;
619547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
620