blob: bff4933d7535a3d90ab35084898b8d78fef5ef61 [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 Kastenfc3d7072017-03-06 14:58:33 -080053 if (mFudgeFactor > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070054 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;
Glenn Kastenfc3d7072017-03-06 14:58:33 -080079 if (mFudgeFactor > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070080 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 }
Glenn Kastenfc3d7072017-03-06 14:58:33 -080089 // genDiff is the difference between the generation count fields of rear and front,
90 // and is always a multiple of mFrameCountP2.
Glenn Kasten9b4fe472016-06-13 09:34:57 -070091 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kastenfc3d7072017-03-06 14:58:33 -080092 // It's OK for writer to be one generation beyond reader,
93 // but reader has lost frames if writer is further than one generation beyond.
94 if (genDiff > mFrameCountP2) {
95 if (lost != NULL) {
96 // Calculate the number of lost frames as the raw difference,
97 // less the mFrameCount frames that are still valid and can be read on retry,
98 // less the wasted indices that don't count as true lost frames.
99 *lost = diff - mFrameCount - mFudgeFactor * (genDiff / mFrameCountP2);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700100 }
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800101 return -EOVERFLOW;
102 }
103 // If writer is one generation beyond reader, skip over the wasted indices.
104 if (genDiff > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700105 diff -= mFudgeFactor;
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800106 // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem.
107 // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6).
108 // So we need to check diff for overflow one more time. See "if" a few lines below.
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800109 }
110 }
111 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700112 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700113 if (lost != NULL) {
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800114 *lost = diff - mFrameCount;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700115 }
116 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700117 }
118 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800119}
120
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800121void audio_utils_fifo_base::shutdown() const
122{
123 ALOGE("%s", __func__);
124 mIsShutdown = true;
125}
126
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700127////////////////////////////////////////////////////////////////////////////////
128
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700129audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700130 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten09acf782016-06-17 10:28:05 -0700131 __attribute__((no_sanitize("integer"))) :
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700132 audio_utils_fifo_base(frameCount, writerRear, throttleFront),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700133 mFrameSize(frameSize), mBuffer(buffer)
Glenn Kasten09acf782016-06-17 10:28:05 -0700134{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700135 // 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 -0700136 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700137 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700138 frameCount > ((uint32_t) INT32_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700139}
140
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700141audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
142 bool throttlesWriter) :
143 audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
144 throttlesWriter ? &mSingleProcessSharedFront : NULL)
145{
146}
147
Glenn Kasten09acf782016-06-17 10:28:05 -0700148audio_utils_fifo::~audio_utils_fifo()
149{
150}
151
152////////////////////////////////////////////////////////////////////////////////
153
Glenn Kasten0f850392016-10-19 12:14:46 -0700154audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
155 mFifo(fifo), mObtained(0), mTotalReleased(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700156{
157}
158
159audio_utils_fifo_provider::~audio_utils_fifo_provider()
160{
161}
162
163////////////////////////////////////////////////////////////////////////////////
164
165audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten0f850392016-10-19 12:14:46 -0700166 audio_utils_fifo_provider(fifo), mLocalRear(0),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800167 mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
168 mIsArmed(true), // because initial fill level of zero is < mArmLevel
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700169 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700170{
171}
172
173audio_utils_fifo_writer::~audio_utils_fifo_writer()
174{
175}
176
Glenn Kastend9942f72016-10-16 14:51:15 -0700177ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
178 const struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700179 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800180{
Glenn Kasten547a9922016-06-15 13:07:31 -0700181 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700182 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700183 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700184 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
185 iovec[0].mLength * mFifo.mFrameSize);
186 if (iovec[1].mLength > 0) {
187 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
188 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
189 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700190 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700191 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700192 }
193 return availToWrite;
194}
195
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700196// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700197ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700198 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700199 __attribute__((no_sanitize("integer")))
200{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700201 int err = 0;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700202 size_t availToWrite;
203 if (mFifo.mThrottleFront != NULL) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700204 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700205 uint32_t front;
206 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800207 front = mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800208 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700209 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700210 if (filled < 0) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700211 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700212 err = filled;
213 availToWrite = 0;
214 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700215 }
216 availToWrite = mEffectiveFrames > (uint32_t) filled ?
217 mEffectiveFrames - (uint32_t) filled : 0;
218 // TODO pull out "count == 0"
219 if (count == 0 || availToWrite > 0 || timeout == NULL ||
220 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
221 break;
222 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700223 // TODO add comments
224 // TODO abstract out switch and replace by general sync object
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700225 // the high level code (synchronization, sleep, futex, iovec) should be completely
226 // separate from the low level code (indexes, available, masking).
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700227 int op = FUTEX_WAIT;
228 switch (mFifo.mThrottleFrontSync) {
229 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800230 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
231 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700232 if (err < 0) {
233 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
234 err = -errno;
235 } else {
236 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700237 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700238 break;
239 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
240 op = FUTEX_WAIT_PRIVATE;
241 // fall through
242 case AUDIO_UTILS_FIFO_SYNC_SHARED:
243 if (timeout->tv_sec == LONG_MAX) {
244 timeout = NULL;
245 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800246 err = mFifo.mThrottleFront->wait(op, front, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700247 if (err < 0) {
248 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700249 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700250 // Benign race condition with partner: mFifo.mThrottleFront->mIndex
251 // changed value between the earlier atomic_load_explicit() and sys_futex().
252 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700253 if (retries-- > 0) {
254 // bypass the "timeout = NULL;" below
255 continue;
256 }
257 // fall through
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700258 case EINTR:
259 case ETIMEDOUT:
260 err = -errno;
261 break;
262 default:
263 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
264 break;
265 }
266 }
267 break;
268 default:
269 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
270 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700271 }
272 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700273 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700274 } else {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800275 if (mFifo.mIsShutdown) {
276 err = -EIO;
277 availToWrite = 0;
278 } else {
279 availToWrite = mEffectiveFrames;
280 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700281 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800282 if (availToWrite > count) {
283 availToWrite = count;
284 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700285 uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
286 size_t part1 = mFifo.mFrameCount - rearOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800287 if (part1 > availToWrite) {
288 part1 = availToWrite;
289 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700290 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700291 // return slice
292 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700293 iovec[0].mOffset = rearOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700294 iovec[0].mLength = part1;
295 iovec[1].mOffset = 0;
296 iovec[1].mLength = part2;
297 mObtained = availToWrite;
298 }
299 return availToWrite > 0 ? availToWrite : err;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800300}
301
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700302void audio_utils_fifo_writer::release(size_t count)
303 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700304{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800305 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten547a9922016-06-15 13:07:31 -0700306 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800307 if (count > mObtained) {
308 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
309 mFifo.shutdown();
310 return;
311 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700312 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800313 uint32_t front = mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800314 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700315 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700316 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800317 mFifo.mWriterRear.storeRelease(mLocalRear);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700318 // TODO add comments
319 int op = FUTEX_WAKE;
320 switch (mFifo.mWriterRearSync) {
321 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
322 break;
323 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
324 op = FUTEX_WAKE_PRIVATE;
325 // fall through
326 case AUDIO_UTILS_FIFO_SYNC_SHARED:
327 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800328 if ((uint32_t) filled < mArmLevel) {
329 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700330 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800331 if (mIsArmed && filled + count > mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800332 int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700333 // err is number of processes woken up
334 if (err < 0) {
335 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
336 __func__, err, errno);
337 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800338 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700339 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700340 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700341 break;
342 default:
343 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
344 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700345 }
346 } else {
347 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800348 mFifo.mWriterRear.storeRelease(mLocalRear);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700349 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700350 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700351 mTotalReleased += count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700352 }
353}
354
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700355ssize_t audio_utils_fifo_writer::available()
356{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700357 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700358 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
359}
360
361void audio_utils_fifo_writer::resize(uint32_t frameCount)
362{
363 // cap to range [0, mFifo.mFrameCount]
364 if (frameCount > mFifo.mFrameCount) {
365 frameCount = mFifo.mFrameCount;
366 }
367 // if we reduce the effective frame count, update hysteresis points to be within the new range
368 if (frameCount < mEffectiveFrames) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800369 if (mArmLevel > frameCount) {
370 mArmLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700371 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800372 if (mTriggerLevel > frameCount) {
373 mTriggerLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700374 }
375 }
376 mEffectiveFrames = frameCount;
377}
378
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700379uint32_t audio_utils_fifo_writer::size() const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700380{
381 return mEffectiveFrames;
382}
383
384void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
385{
386 // cap to range [0, mEffectiveFrames]
387 if (lowLevelArm > mEffectiveFrames) {
388 lowLevelArm = mEffectiveFrames;
389 }
390 if (highLevelTrigger > mEffectiveFrames) {
391 highLevelTrigger = mEffectiveFrames;
392 }
393 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800394 if (lowLevelArm > mArmLevel) {
395 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700396 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800397 mArmLevel = lowLevelArm;
398 mTriggerLevel = highLevelTrigger;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700399}
400
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800401void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700402{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800403 *armLevel = mArmLevel;
404 *triggerLevel = mTriggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700405}
406
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700407////////////////////////////////////////////////////////////////////////////////
408
409audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kasten2f995312016-12-16 12:42:26 -0800410 audio_utils_fifo_provider(fifo),
411
412 // If we throttle the writer, then initialize our front index to zero so that we see all data
413 // currently in the buffer.
414 // Otherwise, ignore everything currently in the buffer by initializing our front index to the
415 // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case
416 // where reader starts out more than one buffer behind writer. The initial catch-up does not
417 // contribute towards the totalLost, totalFlushed, or totalReleased counters.
418 mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadConsume()),
419
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700420 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800421 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
422 mIsArmed(true), // because initial fill level of zero is > mArmLevel
Glenn Kasten0f850392016-10-19 12:14:46 -0700423 mTotalLost(0), mTotalFlushed(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700424{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700425}
426
427audio_utils_fifo_reader::~audio_utils_fifo_reader()
428{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700429 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700430}
431
Glenn Kastend9942f72016-10-16 14:51:15 -0700432ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700433 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700434 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800435{
Glenn Kasten547a9922016-06-15 13:07:31 -0700436 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700437 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700438 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700439 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
440 iovec[0].mLength * mFifo.mFrameSize);
441 if (iovec[1].mLength > 0) {
442 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
443 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
444 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700445 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700446 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700447 }
448 return availToRead;
449}
450
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700451ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700452 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700453 __attribute__((no_sanitize("integer")))
454{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700455 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700456}
457
458void audio_utils_fifo_reader::release(size_t count)
459 __attribute__((no_sanitize("integer")))
460{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800461 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700462 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800463 if (count > mObtained) {
464 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
465 mFifo.shutdown();
466 return;
467 }
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700468 if (mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800469 uint32_t rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800470 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700471 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700472 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800473 mThrottleFront->storeRelease(mLocalFront);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700474 // TODO add comments
475 int op = FUTEX_WAKE;
476 switch (mFifo.mThrottleFrontSync) {
477 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
478 break;
479 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
480 op = FUTEX_WAKE_PRIVATE;
481 // fall through
482 case AUDIO_UTILS_FIFO_SYNC_SHARED:
483 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800484 if (filled > mArmLevel) {
485 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700486 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800487 if (mIsArmed && filled - count < mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800488 int err = mThrottleFront->wake(op, 1 /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700489 // err is number of processes woken up
490 if (err < 0 || err > 1) {
491 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
492 __func__, err, errno);
493 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800494 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700495 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700496 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700497 break;
498 default:
499 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
500 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700501 }
502 } else {
503 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700504 }
505 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700506 mTotalReleased += count;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700507 }
508}
509
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700510// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700511ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700512 const struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700513 __attribute__((no_sanitize("integer")))
514{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700515 int err = 0;
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700516 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700517 uint32_t rear;
518 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800519 rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700520 // TODO pull out "count == 0"
521 if (count == 0 || rear != mLocalFront || timeout == NULL ||
522 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
523 break;
524 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700525 // TODO add comments
526 int op = FUTEX_WAIT;
527 switch (mFifo.mWriterRearSync) {
528 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800529 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
530 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700531 if (err < 0) {
532 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
533 err = -errno;
534 } else {
535 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700536 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700537 break;
538 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
539 op = FUTEX_WAIT_PRIVATE;
540 // fall through
541 case AUDIO_UTILS_FIFO_SYNC_SHARED:
542 if (timeout->tv_sec == LONG_MAX) {
543 timeout = NULL;
544 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800545 err = mFifo.mWriterRear.wait(op, rear, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700546 if (err < 0) {
547 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700548 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700549 // Benign race condition with partner: mFifo.mWriterRear->mIndex
550 // changed value between the earlier atomic_load_explicit() and sys_futex().
551 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700552 if (retries-- > 0) {
553 // bypass the "timeout = NULL;" below
554 continue;
555 }
556 // fall through
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700557 case EINTR:
558 case ETIMEDOUT:
559 err = -errno;
560 break;
561 default:
562 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
563 break;
564 }
565 }
566 break;
567 default:
568 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
569 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700570 }
571 timeout = NULL;
572 }
Glenn Kasten0f850392016-10-19 12:14:46 -0700573 size_t ourLost;
574 if (lost == NULL) {
575 lost = &ourLost;
576 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800577 // returns -EIO if mIsShutdown
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700578 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten0f850392016-10-19 12:14:46 -0700579 mTotalLost += *lost;
580 mTotalReleased += *lost;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700581 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700582 if (filled == -EOVERFLOW) {
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800583 // catch up with writer, but preserve the still valid frames in buffer
584 mLocalFront = rear - mFifo.mFrameCountP2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700585 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700586 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700587 err = filled;
588 filled = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700589 }
590 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800591 if (availToRead > count) {
592 availToRead = count;
593 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700594 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
595 size_t part1 = mFifo.mFrameCount - frontOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800596 if (part1 > availToRead) {
597 part1 = availToRead;
598 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700599 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700600 // return slice
601 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700602 iovec[0].mOffset = frontOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700603 iovec[0].mLength = part1;
604 iovec[1].mOffset = 0;
605 iovec[1].mLength = part2;
606 mObtained = availToRead;
607 }
608 return availToRead > 0 ? availToRead : err;
609}
610
611ssize_t audio_utils_fifo_reader::available()
612{
613 return available(NULL /*lost*/);
614}
615
616ssize_t audio_utils_fifo_reader::available(size_t *lost)
617{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700618 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700619 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
620}
621
Glenn Kasten0f850392016-10-19 12:14:46 -0700622ssize_t audio_utils_fifo_reader::flush(size_t *lost)
623{
624 audio_utils_iovec iovec[2];
625 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
626 if (ret > 0) {
627 size_t flushed = (size_t) ret;
628 release(flushed);
629 mTotalFlushed += flushed;
630 ret = flushed;
631 }
632 return ret;
633}
634
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800635void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700636{
637 // cap to range [0, mFifo.mFrameCount]
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800638 if (armLevel < 0) {
639 armLevel = -1;
640 } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
641 armLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700642 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800643 if (triggerLevel > mFifo.mFrameCount) {
644 triggerLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700645 }
646 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800647 if (armLevel < mArmLevel) {
648 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700649 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800650 mArmLevel = armLevel;
651 mTriggerLevel = triggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700652}
653
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800654void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700655{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800656 *armLevel = mArmLevel;
657 *triggerLevel = mTriggerLevel;
Glenn Kasten547a9922016-06-15 13:07:31 -0700658}