blob: a6dd545c74885d105be34aea372cd96448f5a06b [file] [log] [blame]
Glenn Kasten9b4c8052015-01-06 14:13:13 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "audio_utils_fifo"
19
Glenn Kasten9052f3b2016-07-08 16:24:41 -070020#include <errno.h>
Glenn Kasten0ab1d862016-06-20 12:04:56 -070021#include <limits.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080022#include <stdlib.h>
23#include <string.h>
Glenn Kasten9052f3b2016-07-08 16:24:41 -070024
Glenn Kastenbe9f4d82016-12-01 08:30:21 -080025#include <audio_utils/clock_nanosleep.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080026#include <audio_utils/fifo.h>
Glenn Kastenbe9f4d82016-12-01 08:30:21 -080027#include <audio_utils/futex.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080028#include <audio_utils/roundup.h>
Logan Chien24fcfdd2018-04-23 14:42:50 +080029#include <log/log.h>
Andy Hung74213cb2018-10-09 13:55:11 -070030#include <system/audio.h> // FALLTHROUGH_INTENDED
Glenn Kasten9b4fe472016-06-13 09:34:57 -070031#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080032
Glenn Kastendc1ff1f2016-09-02 13:54:59 -070033audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
Glenn Kastenc0924bc2016-10-02 13:00:19 -070034 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070035 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070036 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070037 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kastenc0924bc2016-10-02 13:00:19 -070038 // FIXME need an API to configure the sync types
39 mWriterRear(writerRear), mWriterRearSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
Glenn Kasten0b2947b2016-11-22 14:00:23 -080040 mThrottleFront(throttleFront), mThrottleFrontSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
41 mIsShutdown(false)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080042{
Glenn Kasten09acf782016-06-17 10:28:05 -070043 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -070044 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080045}
46
Glenn Kasten09acf782016-06-17 10:28:05 -070047audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080048{
49}
50
Glenn Kasten3f115ba2016-11-22 14:00:53 -080051uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const
Glenn Kasten9b4fe472016-06-13 09:34:57 -070052 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080053{
Glenn Kastenfc3d7072017-03-06 14:58:33 -080054 if (mFudgeFactor > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070055 uint32_t mask = mFrameCountP2 - 1;
56 ALOG_ASSERT((index & mask) < mFrameCount);
57 ALOG_ASSERT(increment <= mFrameCountP2);
58 if ((index & mask) + increment >= mFrameCount) {
59 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080060 }
61 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070062 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080063 return index;
64 } else {
65 return index + increment;
66 }
67}
68
Glenn Kasten8c5518a2017-04-17 16:34:38 -070069int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost, bool flush) const
Glenn Kasten9b4fe472016-06-13 09:34:57 -070070 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080071{
Glenn Kasten44001d42016-10-19 15:46:02 -070072 // TODO replace multiple returns by a single return point so this isn't needed
73 if (lost != NULL) {
74 *lost = 0;
75 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -080076 if (mIsShutdown) {
77 return -EIO;
78 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -070079 uint32_t diff = rear - front;
Glenn Kastenfc3d7072017-03-06 14:58:33 -080080 if (mFudgeFactor > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070081 uint32_t mask = mFrameCountP2 - 1;
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -070082 uint32_t rearOffset = rear & mask;
83 uint32_t frontOffset = front & mask;
84 if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -080085 ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u",
86 __func__, frontOffset, rearOffset, mFrameCount);
87 shutdown();
Glenn Kasten6d7ad762016-06-15 17:05:54 -070088 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070089 }
Glenn Kastenfc3d7072017-03-06 14:58:33 -080090 // genDiff is the difference between the generation count fields of rear and front,
91 // and is always a multiple of mFrameCountP2.
Glenn Kasten9b4fe472016-06-13 09:34:57 -070092 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kastenfc3d7072017-03-06 14:58:33 -080093 // It's OK for writer to be one generation beyond reader,
94 // but reader has lost frames if writer is further than one generation beyond.
95 if (genDiff > mFrameCountP2) {
96 if (lost != NULL) {
97 // Calculate the number of lost frames as the raw difference,
98 // less the mFrameCount frames that are still valid and can be read on retry,
99 // less the wasted indices that don't count as true lost frames.
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700100 *lost = diff - (flush ? 0 : mFrameCount) - mFudgeFactor * (genDiff/mFrameCountP2);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700101 }
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800102 return -EOVERFLOW;
103 }
104 // If writer is one generation beyond reader, skip over the wasted indices.
105 if (genDiff > 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700106 diff -= mFudgeFactor;
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800107 // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem.
108 // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6).
109 // So we need to check diff for overflow one more time. See "if" a few lines below.
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800110 }
111 }
112 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700113 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700114 if (lost != NULL) {
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700115 *lost = diff - (flush ? 0 : mFrameCount);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700116 }
117 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700118 }
119 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800120}
121
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800122void audio_utils_fifo_base::shutdown() const
123{
124 ALOGE("%s", __func__);
125 mIsShutdown = true;
126}
127
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700128////////////////////////////////////////////////////////////////////////////////
129
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700130audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700131 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
Glenn Kasten09acf782016-06-17 10:28:05 -0700132 __attribute__((no_sanitize("integer"))) :
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700133 audio_utils_fifo_base(frameCount, writerRear, throttleFront),
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700134 mFrameSize(frameSize), mBuffer(buffer)
Glenn Kasten09acf782016-06-17 10:28:05 -0700135{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700136 // 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 -0700137 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700138 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700139 frameCount > ((uint32_t) INT32_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700140}
141
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700142audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
143 bool throttlesWriter) :
144 audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
145 throttlesWriter ? &mSingleProcessSharedFront : NULL)
146{
147}
148
Glenn Kasten09acf782016-06-17 10:28:05 -0700149audio_utils_fifo::~audio_utils_fifo()
150{
151}
152
153////////////////////////////////////////////////////////////////////////////////
154
Glenn Kasten0f850392016-10-19 12:14:46 -0700155audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
156 mFifo(fifo), mObtained(0), mTotalReleased(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700157{
158}
159
160audio_utils_fifo_provider::~audio_utils_fifo_provider()
161{
162}
163
164////////////////////////////////////////////////////////////////////////////////
165
166audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten0f850392016-10-19 12:14:46 -0700167 audio_utils_fifo_provider(fifo), mLocalRear(0),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800168 mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
169 mIsArmed(true), // because initial fill level of zero is < mArmLevel
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700170 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700171{
172}
173
174audio_utils_fifo_writer::~audio_utils_fifo_writer()
175{
176}
177
Glenn Kastend9942f72016-10-16 14:51:15 -0700178ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
179 const struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700180 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800181{
Glenn Kasten547a9922016-06-15 13:07:31 -0700182 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700183 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700184 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700185 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
186 iovec[0].mLength * mFifo.mFrameSize);
187 if (iovec[1].mLength > 0) {
188 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
189 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
190 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700191 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700192 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700193 }
194 return availToWrite;
195}
196
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700197// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700198ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700199 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700200 __attribute__((no_sanitize("integer")))
201{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700202 int err = 0;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700203 size_t availToWrite;
204 if (mFifo.mThrottleFront != NULL) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700205 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700206 uint32_t front;
207 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800208 front = mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800209 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700210 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700211 if (filled < 0) {
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700212 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700213 err = filled;
214 availToWrite = 0;
215 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700216 }
217 availToWrite = mEffectiveFrames > (uint32_t) filled ?
218 mEffectiveFrames - (uint32_t) filled : 0;
219 // TODO pull out "count == 0"
220 if (count == 0 || availToWrite > 0 || timeout == NULL ||
221 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
222 break;
223 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700224 // TODO add comments
225 // TODO abstract out switch and replace by general sync object
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700226 // the high level code (synchronization, sleep, futex, iovec) should be completely
227 // separate from the low level code (indexes, available, masking).
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700228 int op = FUTEX_WAIT;
229 switch (mFifo.mThrottleFrontSync) {
230 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800231 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
232 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700233 if (err < 0) {
234 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
235 err = -errno;
236 } else {
237 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700238 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700239 break;
240 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
241 op = FUTEX_WAIT_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700242 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700243 case AUDIO_UTILS_FIFO_SYNC_SHARED:
244 if (timeout->tv_sec == LONG_MAX) {
245 timeout = NULL;
246 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800247 err = mFifo.mThrottleFront->wait(op, front, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700248 if (err < 0) {
249 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700250 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700251 // Benign race condition with partner: mFifo.mThrottleFront->mIndex
252 // changed value between the earlier atomic_load_explicit() and sys_futex().
253 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700254 if (retries-- > 0) {
255 // bypass the "timeout = NULL;" below
256 continue;
257 }
Andy Hung74213cb2018-10-09 13:55:11 -0700258 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700259 case EINTR:
260 case ETIMEDOUT:
261 err = -errno;
262 break;
263 default:
264 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
265 break;
266 }
267 }
268 break;
269 default:
270 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
271 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700272 }
273 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700274 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700275 } else {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800276 if (mFifo.mIsShutdown) {
277 err = -EIO;
278 availToWrite = 0;
279 } else {
280 availToWrite = mEffectiveFrames;
281 }
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700282 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800283 if (availToWrite > count) {
284 availToWrite = count;
285 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700286 uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
287 size_t part1 = mFifo.mFrameCount - rearOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800288 if (part1 > availToWrite) {
289 part1 = availToWrite;
290 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700291 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700292 // return slice
293 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700294 iovec[0].mOffset = rearOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700295 iovec[0].mLength = part1;
296 iovec[1].mOffset = 0;
297 iovec[1].mLength = part2;
298 mObtained = availToWrite;
299 }
300 return availToWrite > 0 ? availToWrite : err;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800301}
302
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700303void audio_utils_fifo_writer::release(size_t count)
304 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700305{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800306 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten547a9922016-06-15 13:07:31 -0700307 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800308 if (count > mObtained) {
309 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
310 mFifo.shutdown();
311 return;
312 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700313 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800314 uint32_t front = mFifo.mThrottleFront->loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800315 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700316 int32_t filled = mFifo.diff(mLocalRear, front);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700317 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800318 mFifo.mWriterRear.storeRelease(mLocalRear);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700319 // TODO add comments
320 int op = FUTEX_WAKE;
321 switch (mFifo.mWriterRearSync) {
322 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
323 break;
324 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
325 op = FUTEX_WAKE_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700326 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700327 case AUDIO_UTILS_FIFO_SYNC_SHARED:
328 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800329 if ((uint32_t) filled < mArmLevel) {
330 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700331 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800332 if (mIsArmed && filled + count > mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800333 int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700334 // err is number of processes woken up
335 if (err < 0) {
336 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
337 __func__, err, errno);
338 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800339 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700340 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700341 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700342 break;
343 default:
344 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
345 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700346 }
347 } else {
348 mLocalRear = mFifo.sum(mLocalRear, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800349 mFifo.mWriterRear.storeRelease(mLocalRear);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700350 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700351 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700352 mTotalReleased += count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700353 }
354}
355
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700356ssize_t audio_utils_fifo_writer::available()
357{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700358 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700359 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
360}
361
362void audio_utils_fifo_writer::resize(uint32_t frameCount)
363{
364 // cap to range [0, mFifo.mFrameCount]
365 if (frameCount > mFifo.mFrameCount) {
366 frameCount = mFifo.mFrameCount;
367 }
368 // if we reduce the effective frame count, update hysteresis points to be within the new range
369 if (frameCount < mEffectiveFrames) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800370 if (mArmLevel > frameCount) {
371 mArmLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700372 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800373 if (mTriggerLevel > frameCount) {
374 mTriggerLevel = frameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700375 }
376 }
377 mEffectiveFrames = frameCount;
378}
379
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700380uint32_t audio_utils_fifo_writer::size() const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700381{
382 return mEffectiveFrames;
383}
384
385void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
386{
387 // cap to range [0, mEffectiveFrames]
388 if (lowLevelArm > mEffectiveFrames) {
389 lowLevelArm = mEffectiveFrames;
390 }
391 if (highLevelTrigger > mEffectiveFrames) {
392 highLevelTrigger = mEffectiveFrames;
393 }
394 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800395 if (lowLevelArm > mArmLevel) {
396 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700397 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800398 mArmLevel = lowLevelArm;
399 mTriggerLevel = highLevelTrigger;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700400}
401
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800402void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700403{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800404 *armLevel = mArmLevel;
405 *triggerLevel = mTriggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700406}
407
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700408////////////////////////////////////////////////////////////////////////////////
409
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700410audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter,
411 bool flush) :
Glenn Kasten2f995312016-12-16 12:42:26 -0800412 audio_utils_fifo_provider(fifo),
413
414 // If we throttle the writer, then initialize our front index to zero so that we see all data
415 // currently in the buffer.
416 // Otherwise, ignore everything currently in the buffer by initializing our front index to the
417 // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case
418 // where reader starts out more than one buffer behind writer. The initial catch-up does not
419 // contribute towards the totalLost, totalFlushed, or totalReleased counters.
420 mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadConsume()),
421
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700422 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700423 mFlush(flush),
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800424 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
425 mIsArmed(true), // because initial fill level of zero is > mArmLevel
Glenn Kasten0f850392016-10-19 12:14:46 -0700426 mTotalLost(0), mTotalFlushed(0)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700427{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700428}
429
430audio_utils_fifo_reader::~audio_utils_fifo_reader()
431{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700432 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700433}
434
Glenn Kastend9942f72016-10-16 14:51:15 -0700435ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700436 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700437 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800438{
Glenn Kasten547a9922016-06-15 13:07:31 -0700439 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700440 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700441 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700442 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
443 iovec[0].mLength * mFifo.mFrameSize);
444 if (iovec[1].mLength > 0) {
445 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
446 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
447 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700448 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700449 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700450 }
451 return availToRead;
452}
453
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700454ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700455 const struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700456 __attribute__((no_sanitize("integer")))
457{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700458 return obtain(iovec, count, timeout, NULL /*lost*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700459}
460
461void audio_utils_fifo_reader::release(size_t count)
462 __attribute__((no_sanitize("integer")))
463{
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800464 // no need to do an early check for mIsShutdown, because the extra code executed is harmless
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700465 if (count > 0) {
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800466 if (count > mObtained) {
467 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
468 mFifo.shutdown();
469 return;
470 }
Glenn Kastendc1ff1f2016-09-02 13:54:59 -0700471 if (mThrottleFront != NULL) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800472 uint32_t rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800473 // returns -EIO if mIsShutdown
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700474 int32_t filled = mFifo.diff(rear, mLocalFront);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700475 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800476 mThrottleFront->storeRelease(mLocalFront);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700477 // TODO add comments
478 int op = FUTEX_WAKE;
479 switch (mFifo.mThrottleFrontSync) {
480 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
481 break;
482 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
483 op = FUTEX_WAKE_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700484 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700485 case AUDIO_UTILS_FIFO_SYNC_SHARED:
486 if (filled >= 0) {
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800487 if (filled > mArmLevel) {
488 mIsArmed = true;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700489 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800490 if (mIsArmed && filled - count < mTriggerLevel) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800491 int err = mThrottleFront->wake(op, 1 /*waiters*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700492 // err is number of processes woken up
493 if (err < 0 || err > 1) {
494 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
495 __func__, err, errno);
496 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800497 mIsArmed = false;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700498 }
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700499 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700500 break;
501 default:
502 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
503 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700504 }
505 } else {
506 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700507 }
508 mObtained -= count;
Glenn Kasten0f850392016-10-19 12:14:46 -0700509 mTotalReleased += count;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700510 }
511}
512
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700513// iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700514ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
Glenn Kastend9942f72016-10-16 14:51:15 -0700515 const struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700516 __attribute__((no_sanitize("integer")))
517{
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700518 int err = 0;
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700519 int retries = kRetries;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700520 uint32_t rear;
521 for (;;) {
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800522 rear = mFifo.mWriterRear.loadAcquire();
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700523 // TODO pull out "count == 0"
524 if (count == 0 || rear != mLocalFront || timeout == NULL ||
525 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
526 break;
527 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700528 // TODO add comments
529 int op = FUTEX_WAIT;
530 switch (mFifo.mWriterRearSync) {
531 case AUDIO_UTILS_FIFO_SYNC_SLEEP:
Glenn Kastenbe9f4d82016-12-01 08:30:21 -0800532 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
533 NULL /*remain*/);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700534 if (err < 0) {
535 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
536 err = -errno;
537 } else {
538 err = -ETIMEDOUT;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700539 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700540 break;
541 case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
542 op = FUTEX_WAIT_PRIVATE;
Andy Hung74213cb2018-10-09 13:55:11 -0700543 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700544 case AUDIO_UTILS_FIFO_SYNC_SHARED:
545 if (timeout->tv_sec == LONG_MAX) {
546 timeout = NULL;
547 }
Glenn Kasten7cc8f542016-12-01 16:12:59 -0800548 err = mFifo.mWriterRear.wait(op, rear, timeout);
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700549 if (err < 0) {
550 switch (errno) {
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700551 case EWOULDBLOCK:
Glenn Kasten7cabff92016-10-19 11:13:55 -0700552 // Benign race condition with partner: mFifo.mWriterRear->mIndex
553 // changed value between the earlier atomic_load_explicit() and sys_futex().
554 // Try to load index again, but give up if we are unable to converge.
Glenn Kastenf277a7c2016-10-14 08:51:20 -0700555 if (retries-- > 0) {
556 // bypass the "timeout = NULL;" below
557 continue;
558 }
Andy Hung74213cb2018-10-09 13:55:11 -0700559 FALLTHROUGH_INTENDED;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700560 case EINTR:
561 case ETIMEDOUT:
562 err = -errno;
563 break;
564 default:
565 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
566 break;
567 }
568 }
569 break;
570 default:
571 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
572 break;
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700573 }
574 timeout = NULL;
575 }
Glenn Kasten0f850392016-10-19 12:14:46 -0700576 size_t ourLost;
577 if (lost == NULL) {
578 lost = &ourLost;
579 }
Glenn Kasten0b2947b2016-11-22 14:00:23 -0800580 // returns -EIO if mIsShutdown
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700581 int32_t filled = mFifo.diff(rear, mLocalFront, lost, mFlush);
Glenn Kasten0f850392016-10-19 12:14:46 -0700582 mTotalLost += *lost;
583 mTotalReleased += *lost;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700584 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700585 if (filled == -EOVERFLOW) {
Glenn Kastenfc3d7072017-03-06 14:58:33 -0800586 // catch up with writer, but preserve the still valid frames in buffer
Glenn Kasten8c5518a2017-04-17 16:34:38 -0700587 mLocalFront = rear - (mFlush ? 0 : mFifo.mFrameCountP2 /*sic*/);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700588 }
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700589 // on error, return an empty slice
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700590 err = filled;
591 filled = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700592 }
593 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800594 if (availToRead > count) {
595 availToRead = count;
596 }
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700597 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
598 size_t part1 = mFifo.mFrameCount - frontOffset;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800599 if (part1 > availToRead) {
600 part1 = availToRead;
601 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700602 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700603 // return slice
604 if (iovec != NULL) {
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700605 iovec[0].mOffset = frontOffset;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700606 iovec[0].mLength = part1;
607 iovec[1].mOffset = 0;
608 iovec[1].mLength = part2;
609 mObtained = availToRead;
610 }
611 return availToRead > 0 ? availToRead : err;
612}
613
614ssize_t audio_utils_fifo_reader::available()
615{
616 return available(NULL /*lost*/);
617}
618
619ssize_t audio_utils_fifo_reader::available(size_t *lost)
620{
Glenn Kasten9ddeb2c2016-10-14 08:49:02 -0700621 // iovec == NULL is not part of the public API, but internally it means don't set mObtained
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700622 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
623}
624
Glenn Kasten0f850392016-10-19 12:14:46 -0700625ssize_t audio_utils_fifo_reader::flush(size_t *lost)
626{
627 audio_utils_iovec iovec[2];
628 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
629 if (ret > 0) {
630 size_t flushed = (size_t) ret;
631 release(flushed);
632 mTotalFlushed += flushed;
633 ret = flushed;
634 }
635 return ret;
636}
637
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800638void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700639{
640 // cap to range [0, mFifo.mFrameCount]
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800641 if (armLevel < 0) {
642 armLevel = -1;
643 } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
644 armLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700645 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800646 if (triggerLevel > mFifo.mFrameCount) {
647 triggerLevel = mFifo.mFrameCount;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700648 }
649 // TODO this is overly conservative; it would be better to arm based on actual fill level
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800650 if (armLevel < mArmLevel) {
651 mIsArmed = true;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700652 }
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800653 mArmLevel = armLevel;
654 mTriggerLevel = triggerLevel;
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700655}
656
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800657void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
Glenn Kastenc0924bc2016-10-02 13:00:19 -0700658{
Glenn Kastenb9652ab2016-11-18 13:34:01 -0800659 *armLevel = mArmLevel;
660 *triggerLevel = mTriggerLevel;
Glenn Kasten547a9922016-06-15 13:07:31 -0700661}