blob: ee36cbdb50695986f7d54f951fa6d7a8e0425cce [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 Kasten2f995312016-12-16 12:42:26 -0800400 audio_utils_fifo_provider(fifo),
401
402 // If we throttle the writer, then initialize our front index to zero so that we see all data
403 // currently in the buffer.
404 // Otherwise, ignore everything currently in the buffer by initializing our front index to the
405 // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case
406 // where reader starts out more than one buffer behind writer. The initial catch-up does not
407 // contribute towards the totalLost, totalFlushed, or totalReleased counters.
408 mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadConsume()),
409
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700410 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800411 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
412 mIsArmed(true), // because initial fill level of zero is > mArmLevel
Glenn Kasten0f850392016-10-19 12:14:46 -0700413 mTotalLost(0), mTotalFlushed(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700414{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700415}
416
417audio_utils_fifo_reader::~audio_utils_fifo_reader()
418{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700419 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700420}
421
Glenn Kastend9942f72016-10-16 14:51:15 -0700422ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700423 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700424 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800425{
Glenn Kasten547a9922016-06-15 13:07:31 -0700426 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700427 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700428 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700429 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
430 iovec[0].mLength * mFifo.mFrameSize);
431 if (iovec[1].mLength > 0) {
432 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
433 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
434 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700435 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700436 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700437 }
438 return availToRead;
439}
440
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700441ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700442 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700443 __attribute__((no_sanitize("integer")))
444{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700445 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700446}
447
448void audio_utils_fifo_reader::release(size_t count)
449 __attribute__((no_sanitize("integer")))
450{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800451 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700452 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800453 if (count > mObtained) {
454 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
455 mFifo.shutdown();
456 return;
457 }
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700458 if (mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800459 uint32_t rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800460 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700461 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700462 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800463 mThrottleFront->storeRelease(mLocalFront);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700464 // TODO add comments
465 int op = FUTEX_WAKE;
466 switch (mFifo.mThrottleFrontSync) {
467 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
468 break;
469 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
470 op = FUTEX_WAKE_PRIVATE;
471 // fall through
472 case AUDIO_UTILS_FIFO_SYNC_SHARED:
473 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800474 if (filled > mArmLevel) {
475 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700476 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800477 if (mIsArmed && filled - count < mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800478 int err = mThrottleFront->wake(op, 1 /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700479 // err is number of processes woken up
480 if (err < 0 || err > 1) {
481 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
482 __func__, err, errno);
483 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800484 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700485 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700486 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700487 break;
488 default:
489 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
490 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700491 }
492 } else {
493 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700494 }
495 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700496 mTotalReleased += count;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700497 }
498}
499
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700500// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700501ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700502 const struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700503 __attribute__((no_sanitize("integer")))
504{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700505 int err = 0;
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700506 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700507 uint32_t rear;
508 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800509 rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700510 // TODO pull out "count == 0"
511 if (count == 0 || rear != mLocalFront || timeout == NULL ||
512 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
513 break;
514 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700515 // TODO add comments
516 int op = FUTEX_WAIT;
517 switch (mFifo.mWriterRearSync) {
518 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800519 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
520 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700521 if (err < 0) {
522 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
523 err = -errno;
524 } else {
525 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700526 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700527 break;
528 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
529 op = FUTEX_WAIT_PRIVATE;
530 // fall through
531 case AUDIO_UTILS_FIFO_SYNC_SHARED:
532 if (timeout->tv_sec == LONG_MAX) {
533 timeout = NULL;
534 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800535 err = mFifo.mWriterRear.wait(op, rear, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700536 if (err < 0) {
537 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700538 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700539 // Benign race condition with partner: mFifo.mWriterRear->mIndex
540 // changed value between the earlier atomic_load_explicit() and sys_futex().
541 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700542 if (retries-- > 0) {
543 // bypass the "timeout = NULL;" below
544 continue;
545 }
546 // fall through
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700547 case EINTR:
548 case ETIMEDOUT:
549 err = -errno;
550 break;
551 default:
552 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
553 break;
554 }
555 }
556 break;
557 default:
558 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
559 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700560 }
561 timeout = NULL;
562 }
Glenn Kasten0f850392016-10-19 12:14:46 -0700563 size_t ourLost;
564 if (lost == NULL) {
565 lost = &ourLost;
566 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800567 // returns -EIO if mIsShutdown
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700568 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten0f850392016-10-19 12:14:46 -0700569 mTotalLost += *lost;
570 mTotalReleased += *lost;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700571 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700572 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700573 mLocalFront = rear;
574 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700575 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700576 err = filled;
577 filled = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700578 }
579 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800580 if (availToRead > count) {
581 availToRead = count;
582 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700583 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
584 size_t part1 = mFifo.mFrameCount - frontOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800585 if (part1 > availToRead) {
586 part1 = availToRead;
587 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700588 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700589 // return slice
590 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700591 iovec[0].mOffset = frontOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700592 iovec[0].mLength = part1;
593 iovec[1].mOffset = 0;
594 iovec[1].mLength = part2;
595 mObtained = availToRead;
596 }
597 return availToRead > 0 ? availToRead : err;
598}
599
600ssize_t audio_utils_fifo_reader::available()
601{
602 return available(NULL /*lost*/);
603}
604
605ssize_t audio_utils_fifo_reader::available(size_t *lost)
606{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700607 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700608 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
609}
610
Glenn Kasten0f850392016-10-19 12:14:46 -0700611ssize_t audio_utils_fifo_reader::flush(size_t *lost)
612{
613 audio_utils_iovec iovec[2];
614 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
615 if (ret > 0) {
616 size_t flushed = (size_t) ret;
617 release(flushed);
618 mTotalFlushed += flushed;
619 ret = flushed;
620 }
621 return ret;
622}
623
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800624void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700625{
626 // cap to range [0, mFifo.mFrameCount]
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800627 if (armLevel < 0) {
628 armLevel = -1;
629 } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
630 armLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700631 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800632 if (triggerLevel > mFifo.mFrameCount) {
633 triggerLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700634 }
635 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800636 if (armLevel < mArmLevel) {
637 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700638 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800639 mArmLevel = armLevel;
640 mTriggerLevel = triggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700641}
642
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800643void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700644{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800645 *armLevel = mArmLevel;
646 *triggerLevel = mTriggerLevel;
Glenn Kasten547a9922016-06-15 13:07:31 -0700647}