fifo.cpp revision 2f99531ca3ace4d7d399ac36b4eafc69f8a90e5e
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
25be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten#include <audio_utils/clock_nanosleep.h>
269b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <audio_utils/fifo.h>
27be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten#include <audio_utils/futex.h>
289b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <audio_utils/roundup.h>
299b4c805bc22842480690f14826b729845887963aGlenn Kasten#include <cutils/log.h>
309b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten#include <utils/Errors.h>
319b4c805bc22842480690f14826b729845887963aGlenn Kasten
32dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
33c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
346d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer"))) :
359b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
3609acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    mFudgeFactor(mFrameCountP2 - mFrameCount),
37c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // FIXME need an API to configure the sync types
38c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mWriterRear(writerRear), mWriterRearSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
390b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    mThrottleFront(throttleFront), mThrottleFrontSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
400b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    mIsShutdown(false)
419b4c805bc22842480690f14826b729845887963aGlenn Kasten{
4209acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    // actual upper bound on frameCount will depend on the frame size
439ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX));
449b4c805bc22842480690f14826b729845887963aGlenn Kasten}
459b4c805bc22842480690f14826b729845887963aGlenn Kasten
4609acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenaudio_utils_fifo_base::~audio_utils_fifo_base()
479b4c805bc22842480690f14826b729845887963aGlenn Kasten{
489b4c805bc22842480690f14826b729845887963aGlenn Kasten}
499b4c805bc22842480690f14826b729845887963aGlenn Kasten
503f115bac767924581bb0bef9fcc16df368a7af47Glenn Kastenuint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const
519b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
529b4c805bc22842480690f14826b729845887963aGlenn Kasten{
539b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (mFudgeFactor) {
549b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t mask = mFrameCountP2 - 1;
559b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT((index & mask) < mFrameCount);
569b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT(increment <= mFrameCountP2);
579b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        if ((index & mask) + increment >= mFrameCount) {
589b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            increment += mFudgeFactor;
599b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
609b4c805bc22842480690f14826b729845887963aGlenn Kasten        index += increment;
619b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        ALOG_ASSERT((index & mask) < mFrameCount);
629b4c805bc22842480690f14826b729845887963aGlenn Kasten        return index;
639b4c805bc22842480690f14826b729845887963aGlenn Kasten    } else {
649b4c805bc22842480690f14826b729845887963aGlenn Kasten        return index + increment;
659b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
669b4c805bc22842480690f14826b729845887963aGlenn Kasten}
679b4c805bc22842480690f14826b729845887963aGlenn Kasten
683f115bac767924581bb0bef9fcc16df368a7af47Glenn Kastenint32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost) const
699b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
709b4c805bc22842480690f14826b729845887963aGlenn Kasten{
7144001d498c1718d3405905010d4523df587916cdGlenn Kasten    // TODO replace multiple returns by a single return point so this isn't needed
7244001d498c1718d3405905010d4523df587916cdGlenn Kasten    if (lost != NULL) {
7344001d498c1718d3405905010d4523df587916cdGlenn Kasten        *lost = 0;
7444001d498c1718d3405905010d4523df587916cdGlenn Kasten    }
750b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    if (mIsShutdown) {
760b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        return -EIO;
770b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    }
789b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    uint32_t diff = rear - front;
799b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (mFudgeFactor) {
809b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t mask = mFrameCountP2 - 1;
819ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        uint32_t rearOffset = rear & mask;
829ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        uint32_t frontOffset = front & mask;
839ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) {
840b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u",
850b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten                    __func__, frontOffset, rearOffset, mFrameCount);
860b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            shutdown();
876d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten            return -EIO;
889b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        }
899b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t genDiff = (rear & ~mask) - (front & ~mask);
909b4c805bc22842480690f14826b729845887963aGlenn Kasten        if (genDiff != 0) {
919b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            if (genDiff > mFrameCountP2) {
926d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                if (lost != NULL) {
936d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                    // TODO provide a more accurate estimate
946d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                    *lost = (genDiff / mFrameCountP2) * mFrameCount;
956d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                }
966d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten                return -EOVERFLOW;
979b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            }
989b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            diff -= mFudgeFactor;
999b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
1009b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1019b4c805bc22842480690f14826b729845887963aGlenn Kasten    // FIFO should not be overfull
1029b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (diff > mFrameCount) {
1036d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        if (lost != NULL) {
10444001d498c1718d3405905010d4523df587916cdGlenn Kasten            *lost = diff;
1056d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
1066d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        return -EOVERFLOW;
1079b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
1089b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    return (int32_t) diff;
1099b4c805bc22842480690f14826b729845887963aGlenn Kasten}
1109b4c805bc22842480690f14826b729845887963aGlenn Kasten
1110b2947b464581b0f6e7426c6a2894494fafba324Glenn Kastenvoid audio_utils_fifo_base::shutdown() const
1120b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten{
1130b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    ALOGE("%s", __func__);
1140b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    mIsShutdown = true;
1150b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten}
1160b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten
1176d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
1186d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
119dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
120c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
12109acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten        __attribute__((no_sanitize("integer"))) :
122c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    audio_utils_fifo_base(frameCount, writerRear, throttleFront),
123dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    mFrameSize(frameSize), mBuffer(buffer)
12409acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten{
1259ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    // maximum value of frameCount * frameSize is INT32_MAX (2^31 - 1), not 2^31, because we need to
12609acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    // be able to distinguish successful and error return values from read and write.
1270ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
1289ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten            frameCount > ((uint32_t) INT32_MAX) / frameSize);
12909acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten}
13009acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
131dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
132dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        bool throttlesWriter) :
133dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
134dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        throttlesWriter ?  &mSingleProcessSharedFront : NULL)
135dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten{
136dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten}
137dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten
13809acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenaudio_utils_fifo::~audio_utils_fifo()
13909acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten{
14009acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten}
14109acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
14209acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten////////////////////////////////////////////////////////////////////////////////
14309acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
1440f8503915063b614599fd8016a550b1f408f7c2dGlenn Kastenaudio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
1450f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mFifo(fifo), mObtained(0), mTotalReleased(0)
1466d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1476d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1486d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1496d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_provider::~audio_utils_fifo_provider()
1506d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1516d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1526d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1536d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
1546d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1556d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
1560f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    audio_utils_fifo_provider(fifo), mLocalRear(0),
157b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
158b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mIsArmed(true), // because initial fill level of zero is < mArmLevel
1593ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    mEffectiveFrames(fifo.mFrameCount)
1606d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1616d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1626d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1636d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_writer::~audio_utils_fifo_writer()
1646d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1656d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1666d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
167d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kastenssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
168d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout)
1699b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
1709b4c805bc22842480690f14826b729845887963aGlenn Kasten{
171547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
1723ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    ssize_t availToWrite = obtain(iovec, count, timeout);
173547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToWrite > 0) {
174169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
175169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                iovec[0].mLength * mFifo.mFrameSize);
176169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        if (iovec[1].mLength > 0) {
177169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten            memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
178169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
179169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    iovec[1].mLength * mFifo.mFrameSize);
180547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
1816d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        release(availToWrite);
182547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
183547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToWrite;
184547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
185547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
1869ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten// iovec == NULL is not part of the public API, but internally it means don't set mObtained
1873ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
188d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout)
189547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
190547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
191c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    int err = 0;
1926d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    size_t availToWrite;
1936d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    if (mFifo.mThrottleFront != NULL) {
194f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten        int retries = kRetries;
1953ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        uint32_t front;
1963ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        for (;;) {
1977cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            front = mFifo.mThrottleFront->loadAcquire();
1980b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            // returns -EIO if mIsShutdown
199c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(mLocalRear, front);
2003ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            if (filled < 0) {
201c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // on error, return an empty slice
2029ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten                err = filled;
2039ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten                availToWrite = 0;
2049ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten                break;
2053ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
2063ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            availToWrite = mEffectiveFrames > (uint32_t) filled ?
2073ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    mEffectiveFrames - (uint32_t) filled : 0;
2083ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            // TODO pull out "count == 0"
2093ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            if (count == 0 || availToWrite > 0 || timeout == NULL ||
2103ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
2113ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                break;
2123ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
213c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
214c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO abstract out switch and replace by general sync object
2159ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten            //      the high level code (synchronization, sleep, futex, iovec) should be completely
2169ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten            //      separate from the low level code (indexes, available, masking).
217c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAIT;
218c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mThrottleFrontSync) {
219c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
220be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten                err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
221be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten                        NULL /*remain*/);
222c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (err < 0) {
223c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
224c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -errno;
225c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                } else {
226c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -ETIMEDOUT;
227c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
228c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
229c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
230c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAIT_PRIVATE;
231c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
232c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
233c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (timeout->tv_sec == LONG_MAX) {
234c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    timeout = NULL;
235c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
2367cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten                err = mFifo.mThrottleFront->wait(op, front, timeout);
237c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (err < 0) {
238c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    switch (errno) {
239f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    case EWOULDBLOCK:
2407cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                        // Benign race condition with partner: mFifo.mThrottleFront->mIndex
2417cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                        // changed value between the earlier atomic_load_explicit() and sys_futex().
2427cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                        // Try to load index again, but give up if we are unable to converge.
243f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        if (retries-- > 0) {
244f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                            // bypass the "timeout = NULL;" below
245f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                            continue;
246f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        }
247f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        // fall through
248c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    case EINTR:
249c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    case ETIMEDOUT:
250c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        err = -errno;
251c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        break;
252c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    default:
253c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
254c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        break;
255c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
2563ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
257c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
258c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
259c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
260c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
2613ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
2623ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            timeout = NULL;
2636d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
2646d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    } else {
2650b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        if (mFifo.mIsShutdown) {
2660b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            err = -EIO;
2670b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            availToWrite = 0;
2680b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        } else {
2690b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            availToWrite = mEffectiveFrames;
2700b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        }
2719b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
2729b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToWrite > count) {
2739b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToWrite = count;
2749b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
2759ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
2769ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    size_t part1 = mFifo.mFrameCount - rearOffset;
2779b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToWrite) {
2789b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToWrite;
2799b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
280547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
281c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // return slice
282c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (iovec != NULL) {
2839ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        iovec[0].mOffset = rearOffset;
284c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mLength = part1;
285c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mOffset = 0;
286c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mLength = part2;
287c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mObtained = availToWrite;
288c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
289c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return availToWrite > 0 ? availToWrite : err;
290547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
291547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
2926d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenvoid audio_utils_fifo_writer::release(size_t count)
2936d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
294547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
2950b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    // no need to do an early check for mIsShutdown, because the extra code executed is harmless
296547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (count > 0) {
2970b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        if (count > mObtained) {
2980b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
2990b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            mFifo.shutdown();
3000b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            return;
3010b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        }
3023ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (mFifo.mThrottleFront != NULL) {
3037cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            uint32_t front = mFifo.mThrottleFront->loadAcquire();
3040b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            // returns -EIO if mIsShutdown
305c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(mLocalRear, front);
3063ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalRear = mFifo.sum(mLocalRear, count);
3077cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            mFifo.mWriterRear.storeRelease(mLocalRear);
308c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
309c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAKE;
310c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mWriterRearSync) {
311c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
312c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
313c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
314c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAKE_PRIVATE;
315c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
316c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
317c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (filled >= 0) {
318b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if ((uint32_t) filled < mArmLevel) {
319b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = true;
320c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
321b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if (mIsArmed && filled + count > mTriggerLevel) {
3227cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten                        int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
323c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        // err is number of processes woken up
324c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        if (err < 0) {
325c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                            LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
326c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                    __func__, err, errno);
327c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        }
328b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = false;
3293ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    }
3303ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
331c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
332c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
333c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
334c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
3353ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
3363ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        } else {
3373ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalRear = mFifo.sum(mLocalRear, count);
3387cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            mFifo.mWriterRear.storeRelease(mLocalRear);
3393ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
3406d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        mObtained -= count;
3410f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        mTotalReleased += count;
3426d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    }
3436d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
3446d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
345c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_writer::available()
346c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
3479ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    // iovec == NULL is not part of the public API, but internally it means don't set mObtained
348c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
349c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
350c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
351c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::resize(uint32_t frameCount)
352c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
353c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mFifo.mFrameCount]
354c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (frameCount > mFifo.mFrameCount) {
355c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        frameCount = mFifo.mFrameCount;
356c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
357c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // if we reduce the effective frame count, update hysteresis points to be within the new range
358c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (frameCount < mEffectiveFrames) {
359b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        if (mArmLevel > frameCount) {
360b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten            mArmLevel = frameCount;
361c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
362b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        if (mTriggerLevel > frameCount) {
363b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten            mTriggerLevel = frameCount;
364c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
365c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
366c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mEffectiveFrames = frameCount;
367c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
368c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
3699ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kastenuint32_t audio_utils_fifo_writer::size() const
370c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
371c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return mEffectiveFrames;
372c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
373c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
374c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
375c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
376c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mEffectiveFrames]
377c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (lowLevelArm > mEffectiveFrames) {
378c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        lowLevelArm = mEffectiveFrames;
379c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
380c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (highLevelTrigger > mEffectiveFrames) {
381c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        highLevelTrigger = mEffectiveFrames;
382c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
383c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // TODO this is overly conservative; it would be better to arm based on actual fill level
384b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (lowLevelArm > mArmLevel) {
385b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        mIsArmed = true;
386c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
387b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel = lowLevelArm;
388b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mTriggerLevel = highLevelTrigger;
389c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
390c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
391b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kastenvoid audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
392c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
393b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *armLevel = mArmLevel;
394b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *triggerLevel = mTriggerLevel;
395c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
396c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
3976d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
3986d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
3996d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
4002f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    audio_utils_fifo_provider(fifo),
4012f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten
4022f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // If we throttle the writer, then initialize our front index to zero so that we see all data
4032f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // currently in the buffer.
4042f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // Otherwise, ignore everything currently in the buffer by initializing our front index to the
4052f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // current value of writer's rear.  This avoids an immediate -EOVERFLOW (overrun) in the case
4062f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // where reader starts out more than one buffer behind writer.  The initial catch-up does not
4072f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // contribute towards the totalLost, totalFlushed, or totalReleased counters.
4082f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadConsume()),
4092f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten
410dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
411b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
412b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mIsArmed(true), // because initial fill level of zero is > mArmLevel
4130f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mTotalLost(0), mTotalFlushed(0)
4146d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
4159b4c805bc22842480690f14826b729845887963aGlenn Kasten}
4169b4c805bc22842480690f14826b729845887963aGlenn Kasten
4176d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_reader::~audio_utils_fifo_reader()
4186d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
4190ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
4206d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4216d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
422d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kastenssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
4233ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        size_t *lost)
4249b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
4259b4c805bc22842480690f14826b729845887963aGlenn Kasten{
426547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
4273ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    ssize_t availToRead = obtain(iovec, count, timeout, lost);
428547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToRead > 0) {
429169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
430169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                iovec[0].mLength * mFifo.mFrameSize);
431169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        if (iovec[1].mLength > 0) {
432169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten            memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
433169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
434169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    iovec[1].mLength * mFifo.mFrameSize);
435547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
4366d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        release(availToRead);
437547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
438547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToRead;
439547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
440547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
4413ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
442d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout)
4436d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
4446d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
445c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(iovec, count, timeout, NULL /*lost*/);
4466d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4476d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
4486d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenvoid audio_utils_fifo_reader::release(size_t count)
449547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
450547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
4510b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    // no need to do an early check for mIsShutdown, because the extra code executed is harmless
4526d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    if (count > 0) {
4530b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        if (count > mObtained) {
4540b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
4550b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            mFifo.shutdown();
4560b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            return;
4570b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        }
458dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        if (mThrottleFront != NULL) {
4597cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            uint32_t rear = mFifo.mWriterRear.loadAcquire();
4600b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            // returns -EIO if mIsShutdown
461c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(rear, mLocalFront);
4623ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalFront = mFifo.sum(mLocalFront, count);
4637cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            mThrottleFront->storeRelease(mLocalFront);
464c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
465c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAKE;
466c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mThrottleFrontSync) {
467c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
468c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
469c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
470c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAKE_PRIVATE;
471c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
472c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
473c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (filled >= 0) {
474b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if (filled > mArmLevel) {
475b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = true;
476c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
477b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if (mIsArmed && filled - count < mTriggerLevel) {
4787cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten                        int err = mThrottleFront->wake(op, 1 /*waiters*/);
479c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        // err is number of processes woken up
480c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        if (err < 0 || err > 1) {
481c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                            LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
482c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                    __func__, err, errno);
483c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        }
484b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = false;
4853ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    }
4863ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
487c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
488c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
489c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
490c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
4913ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
4923ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        } else {
4933ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalFront = mFifo.sum(mLocalFront, count);
4946d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
4956d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        mObtained -= count;
4960f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        mTotalReleased += count;
4976d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    }
4986d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4996d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
5009ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten// iovec == NULL is not part of the public API, but internally it means don't set mObtained
5013ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
502d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout, size_t *lost)
5036d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
5046d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
505c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    int err = 0;
506f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten    int retries = kRetries;
5073ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    uint32_t rear;
5083ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    for (;;) {
5097cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten        rear = mFifo.mWriterRear.loadAcquire();
5103ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        // TODO pull out "count == 0"
5113ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (count == 0 || rear != mLocalFront || timeout == NULL ||
5123ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
5133ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            break;
5143ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
515c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        // TODO add comments
516c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        int op = FUTEX_WAIT;
517c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        switch (mFifo.mWriterRearSync) {
518c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_SLEEP:
519be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten            err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
520be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten                    NULL /*remain*/);
521c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (err < 0) {
522c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
523c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = -errno;
524c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            } else {
525c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = -ETIMEDOUT;
526c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            }
527c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
528c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
529c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            op = FUTEX_WAIT_PRIVATE;
530c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // fall through
531c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_SHARED:
532c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (timeout->tv_sec == LONG_MAX) {
533c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                timeout = NULL;
534c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            }
5357cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            err = mFifo.mWriterRear.wait(op, rear, timeout);
536c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (err < 0) {
537c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                switch (errno) {
538f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                case EWOULDBLOCK:
5397cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                    // Benign race condition with partner: mFifo.mWriterRear->mIndex
5407cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                    // changed value between the earlier atomic_load_explicit() and sys_futex().
5417cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                    // Try to load index again, but give up if we are unable to converge.
542f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    if (retries-- > 0) {
543f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        // bypass the "timeout = NULL;" below
544f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        continue;
545f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    }
546f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    // fall through
547c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                case EINTR:
548c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                case ETIMEDOUT:
549c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -errno;
550c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    break;
551c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                default:
552c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
553c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    break;
554c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
5553ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
556c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
557c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        default:
558c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
559c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
5603ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
5613ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        timeout = NULL;
5623ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    }
5630f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    size_t ourLost;
5640f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    if (lost == NULL) {
5650f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        lost = &ourLost;
5660f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    }
5670b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    // returns -EIO if mIsShutdown
5686d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    int32_t filled = mFifo.diff(rear, mLocalFront, lost);
5690f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mTotalLost += *lost;
5700f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mTotalReleased += *lost;
5719b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (filled < 0) {
5723ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (filled == -EOVERFLOW) {
5736d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten            mLocalFront = rear;
5746d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
575c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        // on error, return an empty slice
5769ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        err = filled;
5779ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        filled = 0;
5789b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
5799b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t availToRead = (size_t) filled;
5809b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToRead > count) {
5819b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToRead = count;
5829b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
5839ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
5849ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    size_t part1 = mFifo.mFrameCount - frontOffset;
5859b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToRead) {
5869b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToRead;
5879b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
588547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToRead - part1 : 0;
589c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // return slice
590c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (iovec != NULL) {
5919ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        iovec[0].mOffset = frontOffset;
592c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mLength = part1;
593c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mOffset = 0;
594c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mLength = part2;
595c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mObtained = availToRead;
596c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
597c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return availToRead > 0 ? availToRead : err;
598c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
599c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
600c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_reader::available()
601c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
602c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return available(NULL /*lost*/);
603c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
604c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
605c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_reader::available(size_t *lost)
606c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
6079ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    // iovec == NULL is not part of the public API, but internally it means don't set mObtained
608c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
609c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
610c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
6110f8503915063b614599fd8016a550b1f408f7c2dGlenn Kastenssize_t audio_utils_fifo_reader::flush(size_t *lost)
6120f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten{
6130f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    audio_utils_iovec iovec[2];
6140f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
6150f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    if (ret > 0) {
6160f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        size_t flushed = (size_t) ret;
6170f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        release(flushed);
6180f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        mTotalFlushed += flushed;
6190f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        ret = flushed;
6200f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    }
6210f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    return ret;
6220f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten}
6230f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten
624b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kastenvoid audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
625c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
626c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mFifo.mFrameCount]
627b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (armLevel < 0) {
628b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        armLevel = -1;
629b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
630b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        armLevel = mFifo.mFrameCount;
631c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
632b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (triggerLevel > mFifo.mFrameCount) {
633b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        triggerLevel = mFifo.mFrameCount;
634c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
635c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // TODO this is overly conservative; it would be better to arm based on actual fill level
636b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (armLevel < mArmLevel) {
637b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        mIsArmed = true;
638c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
639b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel = armLevel;
640b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mTriggerLevel = triggerLevel;
641c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
642c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
643b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kastenvoid audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
644c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
645b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *armLevel = mArmLevel;
646b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *triggerLevel = mTriggerLevel;
647547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
648