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{
53fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten    if (mFudgeFactor > 0) {
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
688c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kastenint32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost, bool flush) 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;
79fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten    if (mFudgeFactor > 0) {
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        }
89fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        // genDiff is the difference between the generation count fields of rear and front,
90fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        // and is always a multiple of mFrameCountP2.
919b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        uint32_t genDiff = (rear & ~mask) - (front & ~mask);
92fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        // It's OK for writer to be one generation beyond reader,
93fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        // but reader has lost frames if writer is further than one generation beyond.
94fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        if (genDiff > mFrameCountP2) {
95fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten            if (lost != NULL) {
96fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten                // Calculate the number of lost frames as the raw difference,
97fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten                // less the mFrameCount frames that are still valid and can be read on retry,
98fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten                // less the wasted indices that don't count as true lost frames.
998c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kasten                *lost = diff - (flush ? 0 : mFrameCount) - mFudgeFactor * (genDiff/mFrameCountP2);
1009b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            }
101fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten            return -EOVERFLOW;
102fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        }
103fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        // If writer is one generation beyond reader, skip over the wasted indices.
104fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten        if (genDiff > 0) {
1059b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten            diff -= mFudgeFactor;
106fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten            // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem.
107fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten            // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6).
108fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten            // So we need to check diff for overflow one more time. See "if" a few lines below.
1099b4c805bc22842480690f14826b729845887963aGlenn Kasten        }
1109b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
1119b4c805bc22842480690f14826b729845887963aGlenn Kasten    // FIFO should not be overfull
1129b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (diff > mFrameCount) {
1136d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        if (lost != NULL) {
1148c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kasten            *lost = diff - (flush ? 0 : mFrameCount);
1156d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
1166d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        return -EOVERFLOW;
1179b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
1189b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    return (int32_t) diff;
1199b4c805bc22842480690f14826b729845887963aGlenn Kasten}
1209b4c805bc22842480690f14826b729845887963aGlenn Kasten
1210b2947b464581b0f6e7426c6a2894494fafba324Glenn Kastenvoid audio_utils_fifo_base::shutdown() const
1220b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten{
1230b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    ALOGE("%s", __func__);
1240b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    mIsShutdown = true;
1250b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten}
1260b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten
1276d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
1286d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
129dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
130c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
13109acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten        __attribute__((no_sanitize("integer"))) :
132c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    audio_utils_fifo_base(frameCount, writerRear, throttleFront),
133dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    mFrameSize(frameSize), mBuffer(buffer)
13409acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten{
1359ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    // maximum value of frameCount * frameSize is INT32_MAX (2^31 - 1), not 2^31, because we need to
13609acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten    // be able to distinguish successful and error return values from read and write.
1370ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
1389ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten            frameCount > ((uint32_t) INT32_MAX) / frameSize);
13909acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten}
14009acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
141dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kastenaudio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
142dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        bool throttlesWriter) :
143dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
144dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        throttlesWriter ?  &mSingleProcessSharedFront : NULL)
145dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten{
146dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten}
147dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten
14809acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kastenaudio_utils_fifo::~audio_utils_fifo()
14909acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten{
15009acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten}
15109acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
15209acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten////////////////////////////////////////////////////////////////////////////////
15309acf7816f5ed575051d5d60be60d3c2bccc5ddbGlenn Kasten
1540f8503915063b614599fd8016a550b1f408f7c2dGlenn Kastenaudio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
1550f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mFifo(fifo), mObtained(0), mTotalReleased(0)
1566d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1576d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1586d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1596d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_provider::~audio_utils_fifo_provider()
1606d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1616d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1626d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1636d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
1646d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1656d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
1660f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    audio_utils_fifo_provider(fifo), mLocalRear(0),
167b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
168b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mIsArmed(true), // because initial fill level of zero is < mArmLevel
1693ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    mEffectiveFrames(fifo.mFrameCount)
1706d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1716d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1726d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
1736d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_writer::~audio_utils_fifo_writer()
1746d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
1756d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
1766d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
177d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kastenssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
178d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout)
1799b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
1809b4c805bc22842480690f14826b729845887963aGlenn Kasten{
181547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
1823ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    ssize_t availToWrite = obtain(iovec, count, timeout);
183547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToWrite > 0) {
184169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
185169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                iovec[0].mLength * mFifo.mFrameSize);
186169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        if (iovec[1].mLength > 0) {
187169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten            memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
188169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
189169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    iovec[1].mLength * mFifo.mFrameSize);
190547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
1916d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        release(availToWrite);
192547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
193547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToWrite;
194547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
195547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
1969ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten// iovec == NULL is not part of the public API, but internally it means don't set mObtained
1973ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
198d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout)
199547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
200547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
201c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    int err = 0;
2026d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    size_t availToWrite;
2036d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    if (mFifo.mThrottleFront != NULL) {
204f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten        int retries = kRetries;
2053ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        uint32_t front;
2063ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        for (;;) {
2077cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            front = mFifo.mThrottleFront->loadAcquire();
2080b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            // returns -EIO if mIsShutdown
209c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(mLocalRear, front);
2103ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            if (filled < 0) {
211c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // on error, return an empty slice
2129ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten                err = filled;
2139ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten                availToWrite = 0;
2149ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten                break;
2153ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
2163ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            availToWrite = mEffectiveFrames > (uint32_t) filled ?
2173ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    mEffectiveFrames - (uint32_t) filled : 0;
2183ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            // TODO pull out "count == 0"
2193ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            if (count == 0 || availToWrite > 0 || timeout == NULL ||
2203ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
2213ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                break;
2223ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
223c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
224c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO abstract out switch and replace by general sync object
2259ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten            //      the high level code (synchronization, sleep, futex, iovec) should be completely
2269ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten            //      separate from the low level code (indexes, available, masking).
227c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAIT;
228c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mThrottleFrontSync) {
229c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
230be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten                err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
231be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten                        NULL /*remain*/);
232c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (err < 0) {
233c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
234c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -errno;
235c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                } else {
236c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -ETIMEDOUT;
237c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
238c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
239c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
240c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAIT_PRIVATE;
241c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
242c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
243c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (timeout->tv_sec == LONG_MAX) {
244c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    timeout = NULL;
245c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
2467cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten                err = mFifo.mThrottleFront->wait(op, front, timeout);
247c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (err < 0) {
248c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    switch (errno) {
249f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    case EWOULDBLOCK:
2507cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                        // Benign race condition with partner: mFifo.mThrottleFront->mIndex
2517cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                        // changed value between the earlier atomic_load_explicit() and sys_futex().
2527cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                        // Try to load index again, but give up if we are unable to converge.
253f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        if (retries-- > 0) {
254f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                            // bypass the "timeout = NULL;" below
255f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                            continue;
256f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        }
257f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        // fall through
258c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    case EINTR:
259c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    case ETIMEDOUT:
260c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        err = -errno;
261c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        break;
262c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    default:
263c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
264c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        break;
265c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
2663ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
267c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
268c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
269c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
270c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
2713ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
2723ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            timeout = NULL;
2736d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
2746d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    } else {
2750b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        if (mFifo.mIsShutdown) {
2760b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            err = -EIO;
2770b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            availToWrite = 0;
2780b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        } else {
2790b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            availToWrite = mEffectiveFrames;
2800b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        }
2819b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
2829b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToWrite > count) {
2839b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToWrite = count;
2849b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
2859ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
2869ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    size_t part1 = mFifo.mFrameCount - rearOffset;
2879b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToWrite) {
2889b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToWrite;
2899b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
290547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
291c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // return slice
292c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (iovec != NULL) {
2939ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        iovec[0].mOffset = rearOffset;
294c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mLength = part1;
295c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mOffset = 0;
296c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mLength = part2;
297c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mObtained = availToWrite;
298c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
299c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return availToWrite > 0 ? availToWrite : err;
300547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
301547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
3026d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenvoid audio_utils_fifo_writer::release(size_t count)
3036d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
304547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
3050b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    // no need to do an early check for mIsShutdown, because the extra code executed is harmless
306547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (count > 0) {
3070b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        if (count > mObtained) {
3080b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
3090b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            mFifo.shutdown();
3100b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            return;
3110b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        }
3123ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (mFifo.mThrottleFront != NULL) {
3137cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            uint32_t front = mFifo.mThrottleFront->loadAcquire();
3140b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            // returns -EIO if mIsShutdown
315c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(mLocalRear, front);
3163ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalRear = mFifo.sum(mLocalRear, count);
3177cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            mFifo.mWriterRear.storeRelease(mLocalRear);
318c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
319c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAKE;
320c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mWriterRearSync) {
321c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
322c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
323c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
324c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAKE_PRIVATE;
325c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
326c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
327c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (filled >= 0) {
328b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if ((uint32_t) filled < mArmLevel) {
329b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = true;
330c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
331b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if (mIsArmed && filled + count > mTriggerLevel) {
3327cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten                        int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
333c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        // err is number of processes woken up
334c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        if (err < 0) {
335c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                            LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
336c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                    __func__, err, errno);
337c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        }
338b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = false;
3393ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    }
3403ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
341c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
342c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
343c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
344c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
3453ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
3463ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        } else {
3473ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalRear = mFifo.sum(mLocalRear, count);
3487cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            mFifo.mWriterRear.storeRelease(mLocalRear);
3493ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
3506d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        mObtained -= count;
3510f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        mTotalReleased += count;
3526d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    }
3536d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
3546d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
355c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_writer::available()
356c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
3579ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    // iovec == NULL is not part of the public API, but internally it means don't set mObtained
358c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
359c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
360c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
361c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::resize(uint32_t frameCount)
362c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
363c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mFifo.mFrameCount]
364c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (frameCount > mFifo.mFrameCount) {
365c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        frameCount = mFifo.mFrameCount;
366c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
367c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // if we reduce the effective frame count, update hysteresis points to be within the new range
368c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (frameCount < mEffectiveFrames) {
369b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        if (mArmLevel > frameCount) {
370b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten            mArmLevel = frameCount;
371c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
372b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        if (mTriggerLevel > frameCount) {
373b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten            mTriggerLevel = frameCount;
374c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        }
375c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
376c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    mEffectiveFrames = frameCount;
377c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
378c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
3799ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kastenuint32_t audio_utils_fifo_writer::size() const
380c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
381c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return mEffectiveFrames;
382c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
383c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
384c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenvoid audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
385c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
386c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mEffectiveFrames]
387c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (lowLevelArm > mEffectiveFrames) {
388c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        lowLevelArm = mEffectiveFrames;
389c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
390c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (highLevelTrigger > mEffectiveFrames) {
391c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        highLevelTrigger = mEffectiveFrames;
392c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
393c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // TODO this is overly conservative; it would be better to arm based on actual fill level
394b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (lowLevelArm > mArmLevel) {
395b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        mIsArmed = true;
396c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
397b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel = lowLevelArm;
398b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mTriggerLevel = highLevelTrigger;
399c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
400c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
401b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kastenvoid audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
402c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
403b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *armLevel = mArmLevel;
404b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *triggerLevel = mTriggerLevel;
405c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
406c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
4076d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten////////////////////////////////////////////////////////////////////////////////
4086d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
4098c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kastenaudio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter,
4108c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kasten        bool flush) :
4112f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    audio_utils_fifo_provider(fifo),
4122f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten
4132f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // If we throttle the writer, then initialize our front index to zero so that we see all data
4142f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // currently in the buffer.
4152f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // Otherwise, ignore everything currently in the buffer by initializing our front index to the
4162f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // current value of writer's rear.  This avoids an immediate -EOVERFLOW (overrun) in the case
4172f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // where reader starts out more than one buffer behind writer.  The initial catch-up does not
4182f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    // contribute towards the totalLost, totalFlushed, or totalReleased counters.
4192f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten    mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadConsume()),
4202f99531ca3ace4d7d399ac36b4eafc69f8a90e5eGlenn Kasten
421dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten    mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
4228c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kasten    mFlush(flush),
423b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
424b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mIsArmed(true), // because initial fill level of zero is > mArmLevel
4250f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mTotalLost(0), mTotalFlushed(0)
4266d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
4279b4c805bc22842480690f14826b729845887963aGlenn Kasten}
4289b4c805bc22842480690f14826b729845887963aGlenn Kasten
4296d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenaudio_utils_fifo_reader::~audio_utils_fifo_reader()
4306d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
4310ab1d86bc08d6d94721a87dafd62beedd384ac4bGlenn Kasten    // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
4326d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4336d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
434d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kastenssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
4353ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        size_t *lost)
4369b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten        __attribute__((no_sanitize("integer")))
4379b4c805bc22842480690f14826b729845887963aGlenn Kasten{
438547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    audio_utils_iovec iovec[2];
4393ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    ssize_t availToRead = obtain(iovec, count, timeout, lost);
440547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    if (availToRead > 0) {
441169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
442169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                iovec[0].mLength * mFifo.mFrameSize);
443169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten        if (iovec[1].mLength > 0) {
444169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten            memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
445169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
446169f3a203c9cb698098d29d5353dd6cb71f03992Glenn Kasten                    iovec[1].mLength * mFifo.mFrameSize);
447547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        }
4486d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        release(availToRead);
449547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    }
450547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    return availToRead;
451547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
452547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten
4533ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
454d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout)
4556d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
4566d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
457c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(iovec, count, timeout, NULL /*lost*/);
4586d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
4596d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
4606d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kastenvoid audio_utils_fifo_reader::release(size_t count)
461547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten        __attribute__((no_sanitize("integer")))
462547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten{
4630b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    // no need to do an early check for mIsShutdown, because the extra code executed is harmless
4646d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    if (count > 0) {
4650b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        if (count > mObtained) {
4660b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
4670b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            mFifo.shutdown();
4680b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            return;
4690b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten        }
470dc1ff1f1ee8bdd6baccd558bd4e279ffbbe01400Glenn Kasten        if (mThrottleFront != NULL) {
4717cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            uint32_t rear = mFifo.mWriterRear.loadAcquire();
4720b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten            // returns -EIO if mIsShutdown
473c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int32_t filled = mFifo.diff(rear, mLocalFront);
4743ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalFront = mFifo.sum(mLocalFront, count);
4757cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            mThrottleFront->storeRelease(mLocalFront);
476c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // TODO add comments
477c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            int op = FUTEX_WAKE;
478c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            switch (mFifo.mThrottleFrontSync) {
479c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SLEEP:
480c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
481c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
482c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                op = FUTEX_WAKE_PRIVATE;
483c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                // fall through
484c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            case AUDIO_UTILS_FIFO_SYNC_SHARED:
485c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                if (filled >= 0) {
486b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if (filled > mArmLevel) {
487b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = true;
488c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    }
489b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                    if (mIsArmed && filled - count < mTriggerLevel) {
4907cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten                        int err = mThrottleFront->wake(op, 1 /*waiters*/);
491c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        // err is number of processes woken up
492c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        if (err < 0 || err > 1) {
493c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                            LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
494c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                                    __func__, err, errno);
495c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                        }
496b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten                        mIsArmed = false;
4973ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                    }
4983ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                }
499c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
500c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            default:
501c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
502c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                break;
5033ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
5043ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        } else {
5053ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            mLocalFront = mFifo.sum(mLocalFront, count);
5066d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
5076d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        mObtained -= count;
5080f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        mTotalReleased += count;
5096d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten    }
5106d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten}
5116d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten
5129ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten// iovec == NULL is not part of the public API, but internally it means don't set mObtained
5133ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kastenssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
514d9942f73f2bb5222d1f155aa6a6f317b6396ff72Glenn Kasten        const struct timespec *timeout, size_t *lost)
5156d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        __attribute__((no_sanitize("integer")))
5166d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten{
517c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    int err = 0;
518f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten    int retries = kRetries;
5193ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    uint32_t rear;
5203ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    for (;;) {
5217cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten        rear = mFifo.mWriterRear.loadAcquire();
5223ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        // TODO pull out "count == 0"
5233ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (count == 0 || rear != mLocalFront || timeout == NULL ||
5243ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten                (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
5253ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            break;
5263ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
527c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        // TODO add comments
528c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        int op = FUTEX_WAIT;
529c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        switch (mFifo.mWriterRearSync) {
530c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_SLEEP:
531be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten            err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
532be9f4d88b19a052f4fbafcee3a1f05ff6fdbb6adGlenn Kasten                    NULL /*remain*/);
533c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (err < 0) {
534c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
535c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = -errno;
536c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            } else {
537c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                err = -ETIMEDOUT;
538c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            }
539c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
540c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
541c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            op = FUTEX_WAIT_PRIVATE;
542c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            // fall through
543c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        case AUDIO_UTILS_FIFO_SYNC_SHARED:
544c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (timeout->tv_sec == LONG_MAX) {
545c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                timeout = NULL;
546c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            }
5477cc8f545385d09aaa0c6e081856d7e3c8e500133Glenn Kasten            err = mFifo.mWriterRear.wait(op, rear, timeout);
548c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            if (err < 0) {
549c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                switch (errno) {
550f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                case EWOULDBLOCK:
5517cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                    // Benign race condition with partner: mFifo.mWriterRear->mIndex
5527cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                    // changed value between the earlier atomic_load_explicit() and sys_futex().
5537cabff9c1ea2fde87835267d7924d816d1d9f3cdGlenn Kasten                    // Try to load index again, but give up if we are unable to converge.
554f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    if (retries-- > 0) {
555f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        // bypass the "timeout = NULL;" below
556f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                        continue;
557f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    }
558f277a7caf13e25a9fb9150bb025e92d634b11195Glenn Kasten                    // fall through
559c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                case EINTR:
560c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                case ETIMEDOUT:
561c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    err = -errno;
562c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    break;
563c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                default:
564c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
565c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                    break;
566c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten                }
5673ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten            }
568c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
569c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        default:
570c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
571c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten            break;
5723ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        }
5733ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        timeout = NULL;
5743ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten    }
5750f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    size_t ourLost;
5760f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    if (lost == NULL) {
5770f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        lost = &ourLost;
5780f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    }
5790b2947b464581b0f6e7426c6a2894494fafba324Glenn Kasten    // returns -EIO if mIsShutdown
5808c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kasten    int32_t filled = mFifo.diff(rear, mLocalFront, lost, mFlush);
5810f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mTotalLost += *lost;
5820f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    mTotalReleased += *lost;
5839b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    if (filled < 0) {
5843ddacbbcd6c119d3c47a50a9291fdff91fb98386Glenn Kasten        if (filled == -EOVERFLOW) {
585fc3d70736e4c24cbdc8c91076013c01e487fd4d5Glenn Kasten            // catch up with writer, but preserve the still valid frames in buffer
5868c5518ab1b5382bd047b5f16d8bd06e3c853705bGlenn Kasten            mLocalFront = rear - (mFlush ? 0 : mFifo.mFrameCountP2 /*sic*/);
5876d7ad76b2a2b04f3a61605ca1ca019a80b94d339Glenn Kasten        }
588c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        // on error, return an empty slice
5899ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        err = filled;
5909ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        filled = 0;
5919b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    }
5929b4fe47208fbc80e5a56508fc8e7210fa4d888adGlenn Kasten    size_t availToRead = (size_t) filled;
5939b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (availToRead > count) {
5949b4c805bc22842480690f14826b729845887963aGlenn Kasten        availToRead = count;
5959b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
5969ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
5979ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    size_t part1 = mFifo.mFrameCount - frontOffset;
5989b4c805bc22842480690f14826b729845887963aGlenn Kasten    if (part1 > availToRead) {
5999b4c805bc22842480690f14826b729845887963aGlenn Kasten        part1 = availToRead;
6009b4c805bc22842480690f14826b729845887963aGlenn Kasten    }
601547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten    size_t part2 = part1 > 0 ? availToRead - part1 : 0;
602c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // return slice
603c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    if (iovec != NULL) {
6049ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten        iovec[0].mOffset = frontOffset;
605c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[0].mLength = part1;
606c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mOffset = 0;
607c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        iovec[1].mLength = part2;
608c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten        mObtained = availToRead;
609c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
610c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return availToRead > 0 ? availToRead : err;
611c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
612c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
613c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_reader::available()
614c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
615c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return available(NULL /*lost*/);
616c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
617c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
618c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kastenssize_t audio_utils_fifo_reader::available(size_t *lost)
619c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
6209ddeb2c5c17285f8d0cc9d7db6555d7efee9817bGlenn Kasten    // iovec == NULL is not part of the public API, but internally it means don't set mObtained
621c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
622c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
623c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
6240f8503915063b614599fd8016a550b1f408f7c2dGlenn Kastenssize_t audio_utils_fifo_reader::flush(size_t *lost)
6250f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten{
6260f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    audio_utils_iovec iovec[2];
6270f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
6280f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    if (ret > 0) {
6290f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        size_t flushed = (size_t) ret;
6300f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        release(flushed);
6310f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        mTotalFlushed += flushed;
6320f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten        ret = flushed;
6330f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    }
6340f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten    return ret;
6350f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten}
6360f8503915063b614599fd8016a550b1f408f7c2dGlenn Kasten
637b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kastenvoid audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
638c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
639c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // cap to range [0, mFifo.mFrameCount]
640b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (armLevel < 0) {
641b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        armLevel = -1;
642b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
643b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        armLevel = mFifo.mFrameCount;
644c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
645b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (triggerLevel > mFifo.mFrameCount) {
646b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        triggerLevel = mFifo.mFrameCount;
647c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
648c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    // TODO this is overly conservative; it would be better to arm based on actual fill level
649b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    if (armLevel < mArmLevel) {
650b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten        mIsArmed = true;
651c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten    }
652b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mArmLevel = armLevel;
653b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    mTriggerLevel = triggerLevel;
654c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten}
655c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten
656b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kastenvoid audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
657c0924bc38334c7adbf8cbc9cfa9d00559c002652Glenn Kasten{
658b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *armLevel = mArmLevel;
659b9652ab79b4e0f2ca2ad6963ab4988c7ca8a6c44Glenn Kasten    *triggerLevel = mTriggerLevel;
660547a99206f741bbe5adacd9bf8b75c2d6b2aff0dGlenn Kasten}
661