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