blob: 8f89318ada3fe7451d9da84cc91cffe26f17930e [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>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080029#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070030#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080031
Glenn Kastendc1ff1f2016-09-02 13:54:59 -070032audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
Glenn Kastenc0924bc2016-10-02 13:00:19 -070033 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070034 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070035 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070036 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kastenc0924bc2016-10-02 13:00:19 -070037 // FIXME need an API to configure the sync types
38 mWriterRear(writerRear), mWriterRearSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
Glenn Kasten0b2947b2016-11-22 14:00:23 -080039 mThrottleFront(throttleFront), mThrottleFrontSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
40 mIsShutdown(false)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080041{
Glenn Kasten09acf782016-06-17 10:28:05 -070042 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -070043 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080044}
45
Glenn Kasten09acf782016-06-17 10:28:05 -070046audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080047{
48}
49
Glenn Kasten3f115ba2016-11-22 14:00:53 -080050uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const
Glenn Kasten9b4fe472016-06-13 09:34:57 -070051 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080052{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070053 if (mFudgeFactor) {
54 uint32_t mask = mFrameCountP2 - 1;
55 ALOG_ASSERT((index & mask) < mFrameCount);
56 ALOG_ASSERT(increment <= mFrameCountP2);
57 if ((index & mask) + increment >= mFrameCount) {
58 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080059 }
60 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070061 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080062 return index;
63 } else {
64 return index + increment;
65 }
66}
67
Glenn Kasten3f115ba2016-11-22 14:00:53 -080068int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost) const
Glenn Kasten9b4fe472016-06-13 09:34:57 -070069 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080070{
Glenn Kasten44001d42016-10-19 15:46:02 -070071 // TODO replace multiple returns by a single return point so this isn't needed
72 if (lost != NULL) {
73 *lost = 0;
74 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -080075 if (mIsShutdown) {
76 return -EIO;
77 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -070078 uint32_t diff = rear - front;
79 if (mFudgeFactor) {
80 uint32_t mask = mFrameCountP2 - 1;
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -070081 uint32_t rearOffset = rear & mask;
82 uint32_t frontOffset = front & mask;
83 if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -080084 ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u",
85 __func__, frontOffset, rearOffset, mFrameCount);
86 shutdown();
Glenn Kasten6d7ad762016-06-15 17:05:54 -070087 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070088 }
89 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080090 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070091 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070092 if (lost != NULL) {
93 // TODO provide a more accurate estimate
94 *lost = (genDiff / mFrameCountP2) * mFrameCount;
95 }
96 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070097 }
98 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080099 }
100 }
101 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700102 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700103 if (lost != NULL) {
Glenn Kasten44001d42016-10-19 15:46:02 -0700104 *lost = diff;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700105 }
106 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700107 }
108 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800109}
110
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800111void audio_utils_fifo_base::shutdown() const
112{
113 ALOGE("%s", __func__);
114 mIsShutdown = true;
115}
116
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700117////////////////////////////////////////////////////////////////////////////////
118
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700119audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700120 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten09acf782016-06-17 10:28:05 -0700121 __attribute__((no_sanitize("integer"))) :
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700122 audio_utils_fifo_base(frameCount, writerRear, throttleFront),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700123 mFrameSize(frameSize), mBuffer(buffer)
Glenn Kasten09acf782016-06-17 10:28:05 -0700124{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700125 // 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 -0700126 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700127 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700128 frameCount > ((uint32_t) INT32_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700129}
130
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700131audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
132 bool throttlesWriter) :
133 audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
134 throttlesWriter ? &mSingleProcessSharedFront : NULL)
135{
136}
137
Glenn Kasten09acf782016-06-17 10:28:05 -0700138audio_utils_fifo::~audio_utils_fifo()
139{
140}
141
142////////////////////////////////////////////////////////////////////////////////
143
Glenn Kasten0f850392016-10-19 12:14:46 -0700144audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
145 mFifo(fifo), mObtained(0), mTotalReleased(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700146{
147}
148
149audio_utils_fifo_provider::~audio_utils_fifo_provider()
150{
151}
152
153////////////////////////////////////////////////////////////////////////////////
154
155audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten0f850392016-10-19 12:14:46 -0700156 audio_utils_fifo_provider(fifo), mLocalRear(0),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800157 mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
158 mIsArmed(true), // because initial fill level of zero is < mArmLevel
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700159 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700160{
161}
162
163audio_utils_fifo_writer::~audio_utils_fifo_writer()
164{
165}
166
Glenn Kastend9942f72016-10-16 14:51:15 -0700167ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
168 const struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700169 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800170{
Glenn Kasten547a9922016-06-15 13:07:31 -0700171 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700172 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700173 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700174 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
175 iovec[0].mLength * mFifo.mFrameSize);
176 if (iovec[1].mLength > 0) {
177 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
178 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
179 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700180 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700181 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700182 }
183 return availToWrite;
184}
185
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700186// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700187ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700188 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700189 __attribute__((no_sanitize("integer")))
190{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700191 int err = 0;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700192 size_t availToWrite;
193 if (mFifo.mThrottleFront != NULL) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700194 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700195 uint32_t front;
196 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800197 front = mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800198 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700199 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700200 if (filled < 0) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700201 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700202 err = filled;
203 availToWrite = 0;
204 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700205 }
206 availToWrite = mEffectiveFrames > (uint32_t) filled ?
207 mEffectiveFrames - (uint32_t) filled : 0;
208 // TODO pull out "count == 0"
209 if (count == 0 || availToWrite > 0 || timeout == NULL ||
210 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
211 break;
212 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700213 // TODO add comments
214 // TODO abstract out switch and replace by general sync object
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700215 // the high level code (synchronization, sleep, futex, iovec) should be completely
216 // separate from the low level code (indexes, available, masking).
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700217 int op = FUTEX_WAIT;
218 switch (mFifo.mThrottleFrontSync) {
219 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800220 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
221 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700222 if (err < 0) {
223 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
224 err = -errno;
225 } else {
226 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700227 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700228 break;
229 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
230 op = FUTEX_WAIT_PRIVATE;
231 // fall through
232 case AUDIO_UTILS_FIFO_SYNC_SHARED:
233 if (timeout->tv_sec == LONG_MAX) {
234 timeout = NULL;
235 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800236 err = mFifo.mThrottleFront->wait(op, front, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700237 if (err < 0) {
238 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700239 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700240 // Benign race condition with partner: mFifo.mThrottleFront->mIndex
241 // changed value between the earlier atomic_load_explicit() and sys_futex().
242 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700243 if (retries-- > 0) {
244 // bypass the "timeout = NULL;" below
245 continue;
246 }
247 // fall through
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700248 case EINTR:
249 case ETIMEDOUT:
250 err = -errno;
251 break;
252 default:
253 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
254 break;
255 }
256 }
257 break;
258 default:
259 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
260 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700261 }
262 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700263 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700264 } else {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800265 if (mFifo.mIsShutdown) {
266 err = -EIO;
267 availToWrite = 0;
268 } else {
269 availToWrite = mEffectiveFrames;
270 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700271 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800272 if (availToWrite > count) {
273 availToWrite = count;
274 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700275 uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
276 size_t part1 = mFifo.mFrameCount - rearOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800277 if (part1 > availToWrite) {
278 part1 = availToWrite;
279 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700280 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700281 // return slice
282 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700283 iovec[0].mOffset = rearOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700284 iovec[0].mLength = part1;
285 iovec[1].mOffset = 0;
286 iovec[1].mLength = part2;
287 mObtained = availToWrite;
288 }
289 return availToWrite > 0 ? availToWrite : err;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800290}
291
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700292void audio_utils_fifo_writer::release(size_t count)
293 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700294{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800295 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten547a9922016-06-15 13:07:31 -0700296 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800297 if (count > mObtained) {
298 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
299 mFifo.shutdown();
300 return;
301 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700302 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800303 uint32_t front = mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800304 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700305 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700306 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800307 mFifo.mWriterRear.storeRelease(mLocalRear);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700308 // TODO add comments
309 int op = FUTEX_WAKE;
310 switch (mFifo.mWriterRearSync) {
311 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
312 break;
313 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
314 op = FUTEX_WAKE_PRIVATE;
315 // fall through
316 case AUDIO_UTILS_FIFO_SYNC_SHARED:
317 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800318 if ((uint32_t) filled < mArmLevel) {
319 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700320 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800321 if (mIsArmed && filled + count > mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800322 int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700323 // err is number of processes woken up
324 if (err < 0) {
325 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
326 __func__, err, errno);
327 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800328 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700329 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700330 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700331 break;
332 default:
333 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
334 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700335 }
336 } else {
337 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800338 mFifo.mWriterRear.storeRelease(mLocalRear);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700339 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700340 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700341 mTotalReleased += count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700342 }
343}
344
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700345ssize_t audio_utils_fifo_writer::available()
346{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700347 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700348 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
349}
350
351void audio_utils_fifo_writer::resize(uint32_t frameCount)
352{
353 // cap to range [0, mFifo.mFrameCount]
354 if (frameCount > mFifo.mFrameCount) {
355 frameCount = mFifo.mFrameCount;
356 }
357 // if we reduce the effective frame count, update hysteresis points to be within the new range
358 if (frameCount < mEffectiveFrames) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800359 if (mArmLevel > frameCount) {
360 mArmLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700361 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800362 if (mTriggerLevel > frameCount) {
363 mTriggerLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700364 }
365 }
366 mEffectiveFrames = frameCount;
367}
368
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700369uint32_t audio_utils_fifo_writer::size() const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700370{
371 return mEffectiveFrames;
372}
373
374void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
375{
376 // cap to range [0, mEffectiveFrames]
377 if (lowLevelArm > mEffectiveFrames) {
378 lowLevelArm = mEffectiveFrames;
379 }
380 if (highLevelTrigger > mEffectiveFrames) {
381 highLevelTrigger = mEffectiveFrames;
382 }
383 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800384 if (lowLevelArm > mArmLevel) {
385 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700386 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800387 mArmLevel = lowLevelArm;
388 mTriggerLevel = highLevelTrigger;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700389}
390
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800391void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700392{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800393 *armLevel = mArmLevel;
394 *triggerLevel = mTriggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700395}
396
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700397////////////////////////////////////////////////////////////////////////////////
398
399audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kasten0f850392016-10-19 12:14:46 -0700400 audio_utils_fifo_provider(fifo), mLocalFront(0),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700401 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800402 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
403 mIsArmed(true), // because initial fill level of zero is > mArmLevel
Glenn Kasten0f850392016-10-19 12:14:46 -0700404 mTotalLost(0), mTotalFlushed(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700405{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700406}
407
408audio_utils_fifo_reader::~audio_utils_fifo_reader()
409{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700410 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700411}
412
Glenn Kastend9942f72016-10-16 14:51:15 -0700413ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700414 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700415 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800416{
Glenn Kasten547a9922016-06-15 13:07:31 -0700417 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700418 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700419 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700420 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
421 iovec[0].mLength * mFifo.mFrameSize);
422 if (iovec[1].mLength > 0) {
423 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
424 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
425 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700426 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700427 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700428 }
429 return availToRead;
430}
431
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700432ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700433 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700434 __attribute__((no_sanitize("integer")))
435{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700436 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700437}
438
439void audio_utils_fifo_reader::release(size_t count)
440 __attribute__((no_sanitize("integer")))
441{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800442 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700443 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800444 if (count > mObtained) {
445 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
446 mFifo.shutdown();
447 return;
448 }
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700449 if (mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800450 uint32_t rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800451 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700452 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700453 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800454 mThrottleFront->storeRelease(mLocalFront);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700455 // TODO add comments
456 int op = FUTEX_WAKE;
457 switch (mFifo.mThrottleFrontSync) {
458 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
459 break;
460 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
461 op = FUTEX_WAKE_PRIVATE;
462 // fall through
463 case AUDIO_UTILS_FIFO_SYNC_SHARED:
464 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800465 if (filled > mArmLevel) {
466 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700467 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800468 if (mIsArmed && filled - count < mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800469 int err = mThrottleFront->wake(op, 1 /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700470 // err is number of processes woken up
471 if (err < 0 || err > 1) {
472 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
473 __func__, err, errno);
474 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800475 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700476 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700477 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700478 break;
479 default:
480 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
481 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700482 }
483 } else {
484 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700485 }
486 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700487 mTotalReleased += count;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700488 }
489}
490
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700491// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700492ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700493 const struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700494 __attribute__((no_sanitize("integer")))
495{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700496 int err = 0;
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700497 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700498 uint32_t rear;
499 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800500 rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700501 // TODO pull out "count == 0"
502 if (count == 0 || rear != mLocalFront || timeout == NULL ||
503 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
504 break;
505 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700506 // TODO add comments
507 int op = FUTEX_WAIT;
508 switch (mFifo.mWriterRearSync) {
509 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800510 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
511 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700512 if (err < 0) {
513 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
514 err = -errno;
515 } else {
516 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700517 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700518 break;
519 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
520 op = FUTEX_WAIT_PRIVATE;
521 // fall through
522 case AUDIO_UTILS_FIFO_SYNC_SHARED:
523 if (timeout->tv_sec == LONG_MAX) {
524 timeout = NULL;
525 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800526 err = mFifo.mWriterRear.wait(op, rear, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700527 if (err < 0) {
528 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700529 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700530 // Benign race condition with partner: mFifo.mWriterRear->mIndex
531 // changed value between the earlier atomic_load_explicit() and sys_futex().
532 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700533 if (retries-- > 0) {
534 // bypass the "timeout = NULL;" below
535 continue;
536 }
537 // fall through
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700538 case EINTR:
539 case ETIMEDOUT:
540 err = -errno;
541 break;
542 default:
543 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
544 break;
545 }
546 }
547 break;
548 default:
549 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
550 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700551 }
552 timeout = NULL;
553 }
Glenn Kasten0f850392016-10-19 12:14:46 -0700554 size_t ourLost;
555 if (lost == NULL) {
556 lost = &ourLost;
557 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800558 // returns -EIO if mIsShutdown
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700559 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten0f850392016-10-19 12:14:46 -0700560 mTotalLost += *lost;
561 mTotalReleased += *lost;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700562 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700563 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700564 mLocalFront = rear;
565 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700566 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700567 err = filled;
568 filled = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700569 }
570 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800571 if (availToRead > count) {
572 availToRead = count;
573 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700574 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
575 size_t part1 = mFifo.mFrameCount - frontOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800576 if (part1 > availToRead) {
577 part1 = availToRead;
578 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700579 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700580 // return slice
581 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700582 iovec[0].mOffset = frontOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700583 iovec[0].mLength = part1;
584 iovec[1].mOffset = 0;
585 iovec[1].mLength = part2;
586 mObtained = availToRead;
587 }
588 return availToRead > 0 ? availToRead : err;
589}
590
591ssize_t audio_utils_fifo_reader::available()
592{
593 return available(NULL /*lost*/);
594}
595
596ssize_t audio_utils_fifo_reader::available(size_t *lost)
597{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700598 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700599 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
600}
601
Glenn Kasten0f850392016-10-19 12:14:46 -0700602ssize_t audio_utils_fifo_reader::flush(size_t *lost)
603{
604 audio_utils_iovec iovec[2];
605 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
606 if (ret > 0) {
607 size_t flushed = (size_t) ret;
608 release(flushed);
609 mTotalFlushed += flushed;
610 ret = flushed;
611 }
612 return ret;
613}
614
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800615void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700616{
617 // cap to range [0, mFifo.mFrameCount]
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800618 if (armLevel < 0) {
619 armLevel = -1;
620 } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
621 armLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700622 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800623 if (triggerLevel > mFifo.mFrameCount) {
624 triggerLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700625 }
626 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800627 if (armLevel < mArmLevel) {
628 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700629 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800630 mArmLevel = armLevel;
631 mTriggerLevel = triggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700632}
633
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800634void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700635{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800636 *armLevel = mArmLevel;
637 *triggerLevel = mTriggerLevel;
Glenn Kasten547a9922016-06-15 13:07:31 -0700638}