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