blob: 3e5e667a19e8a283742a05bff9c6fa671dc1041c [file] [log] [blame]
Glenn Kasten9b4c8052015-01-06 14:13:13 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "audio_utils_fifo"
19
Glenn Kasten9052f3b2016-07-08 16:24:41 -070020#include <errno.h>
Glenn Kasten0ab1d862016-06-20 12:04:56 -070021#include <limits.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080022#include <stdlib.h>
23#include <string.h>
Glenn Kasten9052f3b2016-07-08 16:24:41 -070024
Glenn Kastenbe9f4d82016-12-01 08:30:21 -080025#include <audio_utils/clock_nanosleep.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080026#include <audio_utils/fifo.h>
Glenn Kastenbe9f4d82016-12-01 08:30:21 -080027#include <audio_utils/futex.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080028#include <audio_utils/roundup.h>
Logan Chien24fcfdd2018-04-23 14:42:50 +080029#include <log/log.h>
Andy Hung74213cb2018-10-09 13:55:11 -070030#include <system/audio.h> // FALLTHROUGH_INTENDED
Glenn Kasten9b4fe472016-06-13 09:34:57 -070031#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080032
Glenn Kastendc1ff1f2016-09-02 13:54:59 -070033audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
Glenn Kasten1f8bd9f2020-02-20 16:51:43 -080034 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront,
35 audio_utils_fifo_sync sync)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070036 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070037 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070038 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kastenc0924bc2016-10-02 13:00:19 -070039 // FIXME need an API to configure the sync types
Glenn Kasten1f8bd9f2020-02-20 16:51:43 -080040 mWriterRear(writerRear), mWriterRearSync(sync),
41 mThrottleFront(throttleFront), mThrottleFrontSync(sync),
Glenn Kasten0b2947b2016-11-22 14:00:23 -080042 mIsShutdown(false)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080043{
Glenn Kasten09acf782016-06-17 10:28:05 -070044 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -070045 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080046}
47
Glenn Kasten09acf782016-06-17 10:28:05 -070048audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080049{
50}
51
Glenn Kasten3f115ba2016-11-22 14:00:53 -080052uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const
Glenn Kasten9b4fe472016-06-13 09:34:57 -070053 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080054{
Glenn Kastenfc3d7072017-03-06 14:58:33 -080055 if (mFudgeFactor > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070056 uint32_t mask = mFrameCountP2 - 1;
57 ALOG_ASSERT((index & mask) < mFrameCount);
58 ALOG_ASSERT(increment <= mFrameCountP2);
59 if ((index & mask) + increment >= mFrameCount) {
60 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080061 }
62 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070063 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080064 return index;
65 } else {
66 return index + increment;
67 }
68}
69
Glenn Kasten8c5518a2017-04-17 16:34:38 -070070int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost, bool flush) const
Glenn Kasten9b4fe472016-06-13 09:34:57 -070071 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080072{
Glenn Kasten44001d42016-10-19 15:46:02 -070073 // TODO replace multiple returns by a single return point so this isn't needed
74 if (lost != NULL) {
75 *lost = 0;
76 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -080077 if (mIsShutdown) {
78 return -EIO;
79 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -070080 uint32_t diff = rear - front;
Glenn Kastenfc3d7072017-03-06 14:58:33 -080081 if (mFudgeFactor > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070082 uint32_t mask = mFrameCountP2 - 1;
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -070083 uint32_t rearOffset = rear & mask;
84 uint32_t frontOffset = front & mask;
85 if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -080086 ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u",
87 __func__, frontOffset, rearOffset, mFrameCount);
88 shutdown();
Glenn Kasten6d7ad762016-06-15 17:05:54 -070089 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070090 }
Glenn Kastenfc3d7072017-03-06 14:58:33 -080091 // genDiff is the difference between the generation count fields of rear and front,
92 // and is always a multiple of mFrameCountP2.
Glenn Kasten9b4fe472016-06-13 09:34:57 -070093 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kastenfc3d7072017-03-06 14:58:33 -080094 // It's OK for writer to be one generation beyond reader,
95 // but reader has lost frames if writer is further than one generation beyond.
96 if (genDiff > mFrameCountP2) {
97 if (lost != NULL) {
98 // Calculate the number of lost frames as the raw difference,
99 // less the mFrameCount frames that are still valid and can be read on retry,
100 // less the wasted indices that don't count as true lost frames.
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700101 *lost = diff - (flush ? 0 : mFrameCount) - mFudgeFactor * (genDiff/mFrameCountP2);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700102 }
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800103 return -EOVERFLOW;
104 }
105 // If writer is one generation beyond reader, skip over the wasted indices.
106 if (genDiff > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700107 diff -= mFudgeFactor;
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800108 // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem.
109 // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6).
110 // So we need to check diff for overflow one more time. See "if" a few lines below.
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800111 }
112 }
113 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700114 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700115 if (lost != NULL) {
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700116 *lost = diff - (flush ? 0 : mFrameCount);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700117 }
118 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700119 }
120 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800121}
122
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800123void audio_utils_fifo_base::shutdown() const
124{
125 ALOGE("%s", __func__);
126 mIsShutdown = true;
127}
128
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700129////////////////////////////////////////////////////////////////////////////////
130
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700131audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700132 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten09acf782016-06-17 10:28:05 -0700133 __attribute__((no_sanitize("integer"))) :
Glenn Kasten1f8bd9f2020-02-20 16:51:43 -0800134 audio_utils_fifo_base(frameCount, writerRear, throttleFront, AUDIO_UTILS_FIFO_SYNC_SHARED),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700135 mFrameSize(frameSize), mBuffer(buffer)
Glenn Kasten09acf782016-06-17 10:28:05 -0700136{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700137 // maximum value of frameCount * frameSize is INT32_MAX (2^31 - 1), not 2^31, because we need to
Glenn Kasten09acf782016-06-17 10:28:05 -0700138 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700139 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700140 frameCount > ((uint32_t) INT32_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700141}
142
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700143audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
Glenn Kasten1f8bd9f2020-02-20 16:51:43 -0800144 bool throttlesWriter, audio_utils_fifo_sync sync) :
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700145 audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
146 throttlesWriter ? &mSingleProcessSharedFront : NULL)
147{
Glenn Kasten1f8bd9f2020-02-20 16:51:43 -0800148 LOG_ALWAYS_FATAL_IF(sync == AUDIO_UTILS_FIFO_SYNC_SHARED);
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700149}
150
Glenn Kasten09acf782016-06-17 10:28:05 -0700151audio_utils_fifo::~audio_utils_fifo()
152{
153}
154
155////////////////////////////////////////////////////////////////////////////////
156
Glenn Kasten0f850392016-10-19 12:14:46 -0700157audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
158 mFifo(fifo), mObtained(0), mTotalReleased(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700159{
160}
161
162audio_utils_fifo_provider::~audio_utils_fifo_provider()
163{
164}
165
166////////////////////////////////////////////////////////////////////////////////
167
168audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten0f850392016-10-19 12:14:46 -0700169 audio_utils_fifo_provider(fifo), mLocalRear(0),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800170 mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
171 mIsArmed(true), // because initial fill level of zero is < mArmLevel
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700172 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700173{
174}
175
176audio_utils_fifo_writer::~audio_utils_fifo_writer()
177{
178}
179
Glenn Kastend9942f72016-10-16 14:51:15 -0700180ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
181 const struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700182 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800183{
Glenn Kasten547a9922016-06-15 13:07:31 -0700184 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700185 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700186 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700187 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
188 iovec[0].mLength * mFifo.mFrameSize);
189 if (iovec[1].mLength > 0) {
190 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
191 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
192 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700193 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700194 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700195 }
196 return availToWrite;
197}
198
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700199// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700200ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700201 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700202 __attribute__((no_sanitize("integer")))
203{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700204 int err = 0;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700205 size_t availToWrite;
206 if (mFifo.mThrottleFront != NULL) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700207 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700208 for (;;) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800209 uint32_t front = mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
210 mFifo.mThrottleFront->loadSingleThreaded() :
211 mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800212 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700213 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700214 if (filled < 0) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700215 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700216 err = filled;
217 availToWrite = 0;
218 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700219 }
220 availToWrite = mEffectiveFrames > (uint32_t) filled ?
221 mEffectiveFrames - (uint32_t) filled : 0;
222 // TODO pull out "count == 0"
223 if (count == 0 || availToWrite > 0 || timeout == NULL ||
224 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
225 break;
226 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700227 // TODO add comments
228 // TODO abstract out switch and replace by general sync object
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700229 // the high level code (synchronization, sleep, futex, iovec) should be completely
230 // separate from the low level code (indexes, available, masking).
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700231 int op = FUTEX_WAIT;
232 switch (mFifo.mThrottleFrontSync) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800233 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
234 err = -ENOTSUP;
235 break;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700236 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800237 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
238 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700239 if (err < 0) {
240 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
241 err = -errno;
242 } else {
243 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700244 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700245 break;
246 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
247 op = FUTEX_WAIT_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700248 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700249 case AUDIO_UTILS_FIFO_SYNC_SHARED:
250 if (timeout->tv_sec == LONG_MAX) {
251 timeout = NULL;
252 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800253 err = mFifo.mThrottleFront->wait(op, front, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700254 if (err < 0) {
255 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700256 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700257 // Benign race condition with partner: mFifo.mThrottleFront->mIndex
258 // changed value between the earlier atomic_load_explicit() and sys_futex().
259 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700260 if (retries-- > 0) {
261 // bypass the "timeout = NULL;" below
262 continue;
263 }
Andy Hung74213cb2018-10-09 13:55:11 -0700264 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700265 case EINTR:
266 case ETIMEDOUT:
267 err = -errno;
268 break;
269 default:
270 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
271 break;
272 }
273 }
274 break;
275 default:
276 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
277 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700278 }
279 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700280 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700281 } else {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800282 if (mFifo.mIsShutdown) {
283 err = -EIO;
284 availToWrite = 0;
285 } else {
286 availToWrite = mEffectiveFrames;
287 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700288 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800289 if (availToWrite > count) {
290 availToWrite = count;
291 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700292 uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
293 size_t part1 = mFifo.mFrameCount - rearOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800294 if (part1 > availToWrite) {
295 part1 = availToWrite;
296 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700297 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700298 // return slice
299 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700300 iovec[0].mOffset = rearOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700301 iovec[0].mLength = part1;
302 iovec[1].mOffset = 0;
303 iovec[1].mLength = part2;
304 mObtained = availToWrite;
305 }
306 return availToWrite > 0 ? availToWrite : err;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800307}
308
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700309void audio_utils_fifo_writer::release(size_t count)
310 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700311{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800312 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten547a9922016-06-15 13:07:31 -0700313 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800314 if (count > mObtained) {
315 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
316 mFifo.shutdown();
317 return;
318 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700319 if (mFifo.mThrottleFront != NULL) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800320 uint32_t front = mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
321 mFifo.mThrottleFront->loadSingleThreaded() :
322 mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800323 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700324 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700325 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800326 if (mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) {
327 mFifo.mWriterRear.storeSingleThreaded(mLocalRear);
328 } else {
329 mFifo.mWriterRear.storeRelease(mLocalRear);
330 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700331 // TODO add comments
332 int op = FUTEX_WAKE;
333 switch (mFifo.mWriterRearSync) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800334 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700335 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
336 break;
337 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
338 op = FUTEX_WAKE_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700339 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700340 case AUDIO_UTILS_FIFO_SYNC_SHARED:
341 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800342 if ((uint32_t) filled < mArmLevel) {
343 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700344 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800345 if (mIsArmed && filled + count > mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800346 int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700347 // err is number of processes woken up
348 if (err < 0) {
349 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
350 __func__, err, errno);
351 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800352 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700353 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700354 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700355 break;
356 default:
357 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
358 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700359 }
360 } else {
361 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800362 if (mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) {
363 mFifo.mWriterRear.storeSingleThreaded(mLocalRear);
364 } else {
365 mFifo.mWriterRear.storeRelease(mLocalRear);
366 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700367 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700368 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700369 mTotalReleased += count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700370 }
371}
372
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700373ssize_t audio_utils_fifo_writer::available()
374{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700375 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700376 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
377}
378
379void audio_utils_fifo_writer::resize(uint32_t frameCount)
380{
381 // cap to range [0, mFifo.mFrameCount]
382 if (frameCount > mFifo.mFrameCount) {
383 frameCount = mFifo.mFrameCount;
384 }
385 // if we reduce the effective frame count, update hysteresis points to be within the new range
386 if (frameCount < mEffectiveFrames) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800387 if (mArmLevel > frameCount) {
388 mArmLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700389 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800390 if (mTriggerLevel > frameCount) {
391 mTriggerLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700392 }
393 }
394 mEffectiveFrames = frameCount;
395}
396
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700397uint32_t audio_utils_fifo_writer::size() const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700398{
399 return mEffectiveFrames;
400}
401
402void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
403{
404 // cap to range [0, mEffectiveFrames]
405 if (lowLevelArm > mEffectiveFrames) {
406 lowLevelArm = mEffectiveFrames;
407 }
408 if (highLevelTrigger > mEffectiveFrames) {
409 highLevelTrigger = mEffectiveFrames;
410 }
411 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800412 if (lowLevelArm > mArmLevel) {
413 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700414 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800415 mArmLevel = lowLevelArm;
416 mTriggerLevel = highLevelTrigger;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700417}
418
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800419void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700420{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800421 *armLevel = mArmLevel;
422 *triggerLevel = mTriggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700423}
424
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700425////////////////////////////////////////////////////////////////////////////////
426
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700427audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter,
428 bool flush) :
Glenn Kasten2f995312016-12-16 12:42:26 -0800429 audio_utils_fifo_provider(fifo),
430
431 // If we throttle the writer, then initialize our front index to zero so that we see all data
432 // currently in the buffer.
433 // Otherwise, ignore everything currently in the buffer by initializing our front index to the
434 // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case
435 // where reader starts out more than one buffer behind writer. The initial catch-up does not
436 // contribute towards the totalLost, totalFlushed, or totalReleased counters.
Glenn Kasten01144642020-02-20 15:10:51 -0800437 mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadAcquire()),
Glenn Kasten2f995312016-12-16 12:42:26 -0800438
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700439 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700440 mFlush(flush),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800441 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
442 mIsArmed(true), // because initial fill level of zero is > mArmLevel
Glenn Kasten0f850392016-10-19 12:14:46 -0700443 mTotalLost(0), mTotalFlushed(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700444{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700445}
446
447audio_utils_fifo_reader::~audio_utils_fifo_reader()
448{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700449 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700450}
451
Glenn Kastend9942f72016-10-16 14:51:15 -0700452ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700453 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700454 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800455{
Glenn Kasten547a9922016-06-15 13:07:31 -0700456 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700457 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700458 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700459 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
460 iovec[0].mLength * mFifo.mFrameSize);
461 if (iovec[1].mLength > 0) {
462 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
463 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
464 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700465 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700466 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700467 }
468 return availToRead;
469}
470
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700471ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700472 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700473 __attribute__((no_sanitize("integer")))
474{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700475 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700476}
477
478void audio_utils_fifo_reader::release(size_t count)
479 __attribute__((no_sanitize("integer")))
480{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800481 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700482 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800483 if (count > mObtained) {
484 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
485 mFifo.shutdown();
486 return;
487 }
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700488 if (mThrottleFront != NULL) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800489 uint32_t rear = mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
490 mFifo.mWriterRear.loadSingleThreaded() : mFifo.mWriterRear.loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800491 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700492 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700493 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800494 if (mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) {
495 mThrottleFront->storeSingleThreaded(mLocalFront);
496 } else {
497 mThrottleFront->storeRelease(mLocalFront);
498 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700499 // TODO add comments
500 int op = FUTEX_WAKE;
501 switch (mFifo.mThrottleFrontSync) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800502 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700503 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
504 break;
505 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
506 op = FUTEX_WAKE_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700507 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700508 case AUDIO_UTILS_FIFO_SYNC_SHARED:
509 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800510 if (filled > mArmLevel) {
511 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700512 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800513 if (mIsArmed && filled - count < mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800514 int err = mThrottleFront->wake(op, 1 /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700515 // err is number of processes woken up
516 if (err < 0 || err > 1) {
517 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
518 __func__, err, errno);
519 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800520 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700521 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700522 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700523 break;
524 default:
525 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
526 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700527 }
528 } else {
529 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700530 }
531 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700532 mTotalReleased += count;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700533 }
534}
535
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700536// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700537ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700538 const struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700539 __attribute__((no_sanitize("integer")))
540{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700541 int err = 0;
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700542 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700543 uint32_t rear;
544 for (;;) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800545 rear = mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
546 mFifo.mWriterRear.loadSingleThreaded() : mFifo.mWriterRear.loadAcquire();
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700547 // TODO pull out "count == 0"
548 if (count == 0 || rear != mLocalFront || timeout == NULL ||
549 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
550 break;
551 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700552 // TODO add comments
553 int op = FUTEX_WAIT;
554 switch (mFifo.mWriterRearSync) {
Glenn Kastenada0fdb2020-02-20 15:13:40 -0800555 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
556 err = -ENOTSUP;
557 break;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700558 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800559 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
560 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700561 if (err < 0) {
562 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
563 err = -errno;
564 } else {
565 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700566 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700567 break;
568 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
569 op = FUTEX_WAIT_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700570 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700571 case AUDIO_UTILS_FIFO_SYNC_SHARED:
572 if (timeout->tv_sec == LONG_MAX) {
573 timeout = NULL;
574 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800575 err = mFifo.mWriterRear.wait(op, rear, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700576 if (err < 0) {
577 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700578 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700579 // Benign race condition with partner: mFifo.mWriterRear->mIndex
580 // changed value between the earlier atomic_load_explicit() and sys_futex().
581 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700582 if (retries-- > 0) {
583 // bypass the "timeout = NULL;" below
584 continue;
585 }
Andy Hung74213cb2018-10-09 13:55:11 -0700586 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700587 case EINTR:
588 case ETIMEDOUT:
589 err = -errno;
590 break;
591 default:
592 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
593 break;
594 }
595 }
596 break;
597 default:
598 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
599 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700600 }
601 timeout = NULL;
602 }
Glenn Kasten0f850392016-10-19 12:14:46 -0700603 size_t ourLost;
604 if (lost == NULL) {
605 lost = &ourLost;
606 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800607 // returns -EIO if mIsShutdown
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700608 int32_t filled = mFifo.diff(rear, mLocalFront, lost, mFlush);
Glenn Kasten0f850392016-10-19 12:14:46 -0700609 mTotalLost += *lost;
610 mTotalReleased += *lost;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700611 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700612 if (filled == -EOVERFLOW) {
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800613 // catch up with writer, but preserve the still valid frames in buffer
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700614 mLocalFront = rear - (mFlush ? 0 : mFifo.mFrameCountP2 /*sic*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700615 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700616 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700617 err = filled;
618 filled = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700619 }
620 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800621 if (availToRead > count) {
622 availToRead = count;
623 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700624 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
625 size_t part1 = mFifo.mFrameCount - frontOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800626 if (part1 > availToRead) {
627 part1 = availToRead;
628 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700629 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700630 // return slice
631 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700632 iovec[0].mOffset = frontOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700633 iovec[0].mLength = part1;
634 iovec[1].mOffset = 0;
635 iovec[1].mLength = part2;
636 mObtained = availToRead;
637 }
638 return availToRead > 0 ? availToRead : err;
639}
640
641ssize_t audio_utils_fifo_reader::available()
642{
643 return available(NULL /*lost*/);
644}
645
646ssize_t audio_utils_fifo_reader::available(size_t *lost)
647{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700648 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700649 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
650}
651
Glenn Kasten0f850392016-10-19 12:14:46 -0700652ssize_t audio_utils_fifo_reader::flush(size_t *lost)
653{
654 audio_utils_iovec iovec[2];
655 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
656 if (ret > 0) {
657 size_t flushed = (size_t) ret;
658 release(flushed);
659 mTotalFlushed += flushed;
660 ret = flushed;
661 }
662 return ret;
663}
664
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800665void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700666{
667 // cap to range [0, mFifo.mFrameCount]
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800668 if (armLevel < 0) {
669 armLevel = -1;
670 } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
671 armLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700672 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800673 if (triggerLevel > mFifo.mFrameCount) {
674 triggerLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700675 }
676 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800677 if (armLevel < mArmLevel) {
678 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700679 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800680 mArmLevel = armLevel;
681 mTriggerLevel = triggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700682}
683
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800684void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700685{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800686 *armLevel = mArmLevel;
687 *triggerLevel = mTriggerLevel;
Glenn Kasten547a9922016-06-15 13:07:31 -0700688}