blob: 45e648893d45a6d63b1bc1d9a906ea6b42a66af9 [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 Kastenc0924bc2016-10-02 13:00:19 -0700197 front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex, std::memory_order_acquire);
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 }
236 err = sys_futex(&mFifo.mThrottleFront->mIndex, op, front, timeout, NULL, 0);
237 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 Kastendc1ff1f2016-09-02 13:54:59 -0700303 uint32_t front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700304 std::memory_order_acquire);
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800305 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700306 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700307 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700308 atomic_store_explicit(&mFifo.mWriterRear.mIndex, mLocalRear,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700309 std::memory_order_release);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700310 // TODO add comments
311 int op = FUTEX_WAKE;
312 switch (mFifo.mWriterRearSync) {
313 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
314 break;
315 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
316 op = FUTEX_WAKE_PRIVATE;
317 // fall through
318 case AUDIO_UTILS_FIFO_SYNC_SHARED:
319 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800320 if ((uint32_t) filled < mArmLevel) {
321 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700322 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800323 if (mIsArmed && filled + count > mTriggerLevel) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700324 int err = sys_futex(&mFifo.mWriterRear.mIndex,
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700325 op, INT32_MAX /*waiters*/, NULL, NULL, 0);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700326 // err is number of processes woken up
327 if (err < 0) {
328 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
329 __func__, err, errno);
330 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800331 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700332 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700333 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700334 break;
335 default:
336 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
337 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700338 }
339 } else {
340 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700341 atomic_store_explicit(&mFifo.mWriterRear.mIndex, mLocalRear,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700342 std::memory_order_release);
343 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700344 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700345 mTotalReleased += count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700346 }
347}
348
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700349ssize_t audio_utils_fifo_writer::available()
350{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700351 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700352 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
353}
354
355void audio_utils_fifo_writer::resize(uint32_t frameCount)
356{
357 // cap to range [0, mFifo.mFrameCount]
358 if (frameCount > mFifo.mFrameCount) {
359 frameCount = mFifo.mFrameCount;
360 }
361 // if we reduce the effective frame count, update hysteresis points to be within the new range
362 if (frameCount < mEffectiveFrames) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800363 if (mArmLevel > frameCount) {
364 mArmLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700365 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800366 if (mTriggerLevel > frameCount) {
367 mTriggerLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700368 }
369 }
370 mEffectiveFrames = frameCount;
371}
372
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700373uint32_t audio_utils_fifo_writer::size() const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700374{
375 return mEffectiveFrames;
376}
377
378void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
379{
380 // cap to range [0, mEffectiveFrames]
381 if (lowLevelArm > mEffectiveFrames) {
382 lowLevelArm = mEffectiveFrames;
383 }
384 if (highLevelTrigger > mEffectiveFrames) {
385 highLevelTrigger = mEffectiveFrames;
386 }
387 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800388 if (lowLevelArm > mArmLevel) {
389 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700390 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800391 mArmLevel = lowLevelArm;
392 mTriggerLevel = highLevelTrigger;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700393}
394
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800395void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700396{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800397 *armLevel = mArmLevel;
398 *triggerLevel = mTriggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700399}
400
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700401////////////////////////////////////////////////////////////////////////////////
402
403audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kasten0f850392016-10-19 12:14:46 -0700404 audio_utils_fifo_provider(fifo), mLocalFront(0),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700405 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800406 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
407 mIsArmed(true), // because initial fill level of zero is > mArmLevel
Glenn Kasten0f850392016-10-19 12:14:46 -0700408 mTotalLost(0), mTotalFlushed(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700409{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700410}
411
412audio_utils_fifo_reader::~audio_utils_fifo_reader()
413{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700414 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700415}
416
Glenn Kastend9942f72016-10-16 14:51:15 -0700417ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700418 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700419 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800420{
Glenn Kasten547a9922016-06-15 13:07:31 -0700421 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700422 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700423 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700424 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
425 iovec[0].mLength * mFifo.mFrameSize);
426 if (iovec[1].mLength > 0) {
427 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
428 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
429 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700430 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700431 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700432 }
433 return availToRead;
434}
435
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700436ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700437 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700438 __attribute__((no_sanitize("integer")))
439{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700440 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700441}
442
443void audio_utils_fifo_reader::release(size_t count)
444 __attribute__((no_sanitize("integer")))
445{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800446 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700447 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800448 if (count > mObtained) {
449 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
450 mFifo.shutdown();
451 return;
452 }
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700453 if (mThrottleFront != NULL) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700454 uint32_t rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700455 std::memory_order_acquire);
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800456 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700457 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700458 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700459 atomic_store_explicit(&mThrottleFront->mIndex, mLocalFront,
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700460 std::memory_order_release);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700461 // TODO add comments
462 int op = FUTEX_WAKE;
463 switch (mFifo.mThrottleFrontSync) {
464 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
465 break;
466 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
467 op = FUTEX_WAKE_PRIVATE;
468 // fall through
469 case AUDIO_UTILS_FIFO_SYNC_SHARED:
470 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800471 if (filled > mArmLevel) {
472 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700473 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800474 if (mIsArmed && filled - count < mTriggerLevel) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700475 int err = sys_futex(&mThrottleFront->mIndex,
476 op, 1 /*waiters*/, NULL, NULL, 0);
477 // err is number of processes woken up
478 if (err < 0 || err > 1) {
479 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
480 __func__, err, errno);
481 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800482 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700483 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700484 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700485 break;
486 default:
487 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
488 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700489 }
490 } else {
491 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700492 }
493 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700494 mTotalReleased += count;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700495 }
496}
497
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700498// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700499ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700500 const struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700501 __attribute__((no_sanitize("integer")))
502{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700503 int err = 0;
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700504 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700505 uint32_t rear;
506 for (;;) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700507 rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700508 std::memory_order_acquire);
509 // TODO pull out "count == 0"
510 if (count == 0 || rear != mLocalFront || timeout == NULL ||
511 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
512 break;
513 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700514 // TODO add comments
515 int op = FUTEX_WAIT;
516 switch (mFifo.mWriterRearSync) {
517 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800518 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
519 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700520 if (err < 0) {
521 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
522 err = -errno;
523 } else {
524 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700525 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700526 break;
527 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
528 op = FUTEX_WAIT_PRIVATE;
529 // fall through
530 case AUDIO_UTILS_FIFO_SYNC_SHARED:
531 if (timeout->tv_sec == LONG_MAX) {
532 timeout = NULL;
533 }
534 err = sys_futex(&mFifo.mWriterRear.mIndex, op, rear, timeout, NULL, 0);
535 if (err < 0) {
536 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700537 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700538 // Benign race condition with partner: mFifo.mWriterRear->mIndex
539 // changed value between the earlier atomic_load_explicit() and sys_futex().
540 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700541 if (retries-- > 0) {
542 // bypass the "timeout = NULL;" below
543 continue;
544 }
545 // fall through
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700546 case EINTR:
547 case ETIMEDOUT:
548 err = -errno;
549 break;
550 default:
551 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
552 break;
553 }
554 }
555 break;
556 default:
557 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
558 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700559 }
560 timeout = NULL;
561 }
Glenn Kasten0f850392016-10-19 12:14:46 -0700562 size_t ourLost;
563 if (lost == NULL) {
564 lost = &ourLost;
565 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800566 // returns -EIO if mIsShutdown
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700567 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten0f850392016-10-19 12:14:46 -0700568 mTotalLost += *lost;
569 mTotalReleased += *lost;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700570 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700571 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700572 mLocalFront = rear;
573 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700574 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700575 err = filled;
576 filled = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700577 }
578 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800579 if (availToRead > count) {
580 availToRead = count;
581 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700582 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
583 size_t part1 = mFifo.mFrameCount - frontOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800584 if (part1 > availToRead) {
585 part1 = availToRead;
586 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700587 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700588 // return slice
589 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700590 iovec[0].mOffset = frontOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700591 iovec[0].mLength = part1;
592 iovec[1].mOffset = 0;
593 iovec[1].mLength = part2;
594 mObtained = availToRead;
595 }
596 return availToRead > 0 ? availToRead : err;
597}
598
599ssize_t audio_utils_fifo_reader::available()
600{
601 return available(NULL /*lost*/);
602}
603
604ssize_t audio_utils_fifo_reader::available(size_t *lost)
605{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700606 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700607 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
608}
609
Glenn Kasten0f850392016-10-19 12:14:46 -0700610ssize_t audio_utils_fifo_reader::flush(size_t *lost)
611{
612 audio_utils_iovec iovec[2];
613 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
614 if (ret > 0) {
615 size_t flushed = (size_t) ret;
616 release(flushed);
617 mTotalFlushed += flushed;
618 ret = flushed;
619 }
620 return ret;
621}
622
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800623void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700624{
625 // cap to range [0, mFifo.mFrameCount]
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800626 if (armLevel < 0) {
627 armLevel = -1;
628 } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
629 armLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700630 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800631 if (triggerLevel > mFifo.mFrameCount) {
632 triggerLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700633 }
634 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800635 if (armLevel < mArmLevel) {
636 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700637 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800638 mArmLevel = armLevel;
639 mTriggerLevel = triggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700640}
641
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800642void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700643{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800644 *armLevel = mArmLevel;
645 *triggerLevel = mTriggerLevel;
Glenn Kasten547a9922016-06-15 13:07:31 -0700646}