1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker *
4*b9df5ad1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker *
8*b9df5ad1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker *
10*b9df5ad1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker */
16*b9df5ad1SAndroid Build Coastguard Worker
17*b9df5ad1SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "audio_utils_fifo"
19*b9df5ad1SAndroid Build Coastguard Worker
20*b9df5ad1SAndroid Build Coastguard Worker #include <errno.h>
21*b9df5ad1SAndroid Build Coastguard Worker #include <limits.h>
22*b9df5ad1SAndroid Build Coastguard Worker #include <stdlib.h>
23*b9df5ad1SAndroid Build Coastguard Worker #include <string.h>
24*b9df5ad1SAndroid Build Coastguard Worker
25*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/clock_nanosleep.h>
26*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/fifo.h>
27*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/futex.h>
28*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/roundup.h>
29*b9df5ad1SAndroid Build Coastguard Worker #include <log/log.h>
30*b9df5ad1SAndroid Build Coastguard Worker #include <system/audio.h> // FALLTHROUGH_INTENDED
31*b9df5ad1SAndroid Build Coastguard Worker #include <utils/Errors.h>
32*b9df5ad1SAndroid Build Coastguard Worker
audio_utils_fifo_base(uint32_t frameCount,audio_utils_fifo_index & writerRear,audio_utils_fifo_index * throttleFront,audio_utils_fifo_sync sync)33*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
34*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront,
35*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_sync sync)
36*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer"))) :
37*b9df5ad1SAndroid Build Coastguard Worker mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
38*b9df5ad1SAndroid Build Coastguard Worker mFudgeFactor(mFrameCountP2 - mFrameCount),
39*b9df5ad1SAndroid Build Coastguard Worker // FIXME need an API to configure the sync types
40*b9df5ad1SAndroid Build Coastguard Worker mWriterRear(writerRear), mWriterRearSync(sync),
41*b9df5ad1SAndroid Build Coastguard Worker mThrottleFront(throttleFront), mThrottleFrontSync(sync),
42*b9df5ad1SAndroid Build Coastguard Worker mIsShutdown(false)
43*b9df5ad1SAndroid Build Coastguard Worker {
44*b9df5ad1SAndroid Build Coastguard Worker // actual upper bound on frameCount will depend on the frame size
45*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX));
46*b9df5ad1SAndroid Build Coastguard Worker }
47*b9df5ad1SAndroid Build Coastguard Worker
~audio_utils_fifo_base()48*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_base::~audio_utils_fifo_base()
49*b9df5ad1SAndroid Build Coastguard Worker {
50*b9df5ad1SAndroid Build Coastguard Worker }
51*b9df5ad1SAndroid Build Coastguard Worker
sum(uint32_t index,uint32_t increment) const52*b9df5ad1SAndroid Build Coastguard Worker uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const
53*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
54*b9df5ad1SAndroid Build Coastguard Worker {
55*b9df5ad1SAndroid Build Coastguard Worker if (mFudgeFactor > 0) {
56*b9df5ad1SAndroid Build Coastguard Worker uint32_t mask = mFrameCountP2 - 1;
57*b9df5ad1SAndroid Build Coastguard Worker ALOG_ASSERT((index & mask) < mFrameCount);
58*b9df5ad1SAndroid Build Coastguard Worker ALOG_ASSERT(increment <= mFrameCountP2);
59*b9df5ad1SAndroid Build Coastguard Worker if ((index & mask) + increment >= mFrameCount) {
60*b9df5ad1SAndroid Build Coastguard Worker increment += mFudgeFactor;
61*b9df5ad1SAndroid Build Coastguard Worker }
62*b9df5ad1SAndroid Build Coastguard Worker index += increment;
63*b9df5ad1SAndroid Build Coastguard Worker ALOG_ASSERT((index & mask) < mFrameCount);
64*b9df5ad1SAndroid Build Coastguard Worker return index;
65*b9df5ad1SAndroid Build Coastguard Worker } else {
66*b9df5ad1SAndroid Build Coastguard Worker return index + increment;
67*b9df5ad1SAndroid Build Coastguard Worker }
68*b9df5ad1SAndroid Build Coastguard Worker }
69*b9df5ad1SAndroid Build Coastguard Worker
diff(uint32_t rear,uint32_t front,size_t * lost,bool flush) const70*b9df5ad1SAndroid Build Coastguard Worker int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost, bool flush) const
71*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
72*b9df5ad1SAndroid Build Coastguard Worker {
73*b9df5ad1SAndroid Build Coastguard Worker // TODO replace multiple returns by a single return point so this isn't needed
74*b9df5ad1SAndroid Build Coastguard Worker if (lost != NULL) {
75*b9df5ad1SAndroid Build Coastguard Worker *lost = 0;
76*b9df5ad1SAndroid Build Coastguard Worker }
77*b9df5ad1SAndroid Build Coastguard Worker if (mIsShutdown) {
78*b9df5ad1SAndroid Build Coastguard Worker return -EIO;
79*b9df5ad1SAndroid Build Coastguard Worker }
80*b9df5ad1SAndroid Build Coastguard Worker uint32_t diff = rear - front;
81*b9df5ad1SAndroid Build Coastguard Worker if (mFudgeFactor > 0) {
82*b9df5ad1SAndroid Build Coastguard Worker uint32_t mask = mFrameCountP2 - 1;
83*b9df5ad1SAndroid Build Coastguard Worker uint32_t rearOffset = rear & mask;
84*b9df5ad1SAndroid Build Coastguard Worker uint32_t frontOffset = front & mask;
85*b9df5ad1SAndroid Build Coastguard Worker if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) {
86*b9df5ad1SAndroid Build Coastguard Worker ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u",
87*b9df5ad1SAndroid Build Coastguard Worker __func__, frontOffset, rearOffset, mFrameCount);
88*b9df5ad1SAndroid Build Coastguard Worker shutdown();
89*b9df5ad1SAndroid Build Coastguard Worker return -EIO;
90*b9df5ad1SAndroid Build Coastguard Worker }
91*b9df5ad1SAndroid Build Coastguard Worker // genDiff is the difference between the generation count fields of rear and front,
92*b9df5ad1SAndroid Build Coastguard Worker // and is always a multiple of mFrameCountP2.
93*b9df5ad1SAndroid Build Coastguard Worker uint32_t genDiff = (rear & ~mask) - (front & ~mask);
94*b9df5ad1SAndroid Build Coastguard Worker // It's OK for writer to be one generation beyond reader,
95*b9df5ad1SAndroid Build Coastguard Worker // but reader has lost frames if writer is further than one generation beyond.
96*b9df5ad1SAndroid Build Coastguard Worker if (genDiff > mFrameCountP2) {
97*b9df5ad1SAndroid Build Coastguard Worker if (lost != NULL) {
98*b9df5ad1SAndroid Build Coastguard Worker // Calculate the number of lost frames as the raw difference,
99*b9df5ad1SAndroid Build Coastguard Worker // less the mFrameCount frames that are still valid and can be read on retry,
100*b9df5ad1SAndroid Build Coastguard Worker // less the wasted indices that don't count as true lost frames.
101*b9df5ad1SAndroid Build Coastguard Worker *lost = diff - (flush ? 0 : mFrameCount) - mFudgeFactor * (genDiff/mFrameCountP2);
102*b9df5ad1SAndroid Build Coastguard Worker }
103*b9df5ad1SAndroid Build Coastguard Worker return -EOVERFLOW;
104*b9df5ad1SAndroid Build Coastguard Worker }
105*b9df5ad1SAndroid Build Coastguard Worker // If writer is one generation beyond reader, skip over the wasted indices.
106*b9df5ad1SAndroid Build Coastguard Worker if (genDiff > 0) {
107*b9df5ad1SAndroid Build Coastguard Worker diff -= mFudgeFactor;
108*b9df5ad1SAndroid Build Coastguard Worker // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem.
109*b9df5ad1SAndroid Build Coastguard Worker // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6).
110*b9df5ad1SAndroid Build Coastguard Worker // So we need to check diff for overflow one more time. See "if" a few lines below.
111*b9df5ad1SAndroid Build Coastguard Worker }
112*b9df5ad1SAndroid Build Coastguard Worker }
113*b9df5ad1SAndroid Build Coastguard Worker // FIFO should not be overfull
114*b9df5ad1SAndroid Build Coastguard Worker if (diff > mFrameCount) {
115*b9df5ad1SAndroid Build Coastguard Worker if (lost != NULL) {
116*b9df5ad1SAndroid Build Coastguard Worker *lost = diff - (flush ? 0 : mFrameCount);
117*b9df5ad1SAndroid Build Coastguard Worker }
118*b9df5ad1SAndroid Build Coastguard Worker return -EOVERFLOW;
119*b9df5ad1SAndroid Build Coastguard Worker }
120*b9df5ad1SAndroid Build Coastguard Worker return (int32_t) diff;
121*b9df5ad1SAndroid Build Coastguard Worker }
122*b9df5ad1SAndroid Build Coastguard Worker
shutdown() const123*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_base::shutdown() const
124*b9df5ad1SAndroid Build Coastguard Worker {
125*b9df5ad1SAndroid Build Coastguard Worker ALOGE("%s", __func__);
126*b9df5ad1SAndroid Build Coastguard Worker mIsShutdown = true;
127*b9df5ad1SAndroid Build Coastguard Worker }
128*b9df5ad1SAndroid Build Coastguard Worker
129*b9df5ad1SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
130*b9df5ad1SAndroid Build Coastguard Worker
audio_utils_fifo(uint32_t frameCount,uint32_t frameSize,void * buffer,audio_utils_fifo_index & writerRear,audio_utils_fifo_index * throttleFront)131*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
132*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
133*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer"))) :
134*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_base(frameCount, writerRear, throttleFront, AUDIO_UTILS_FIFO_SYNC_SHARED),
135*b9df5ad1SAndroid Build Coastguard Worker mFrameSize(frameSize), mBuffer(buffer)
136*b9df5ad1SAndroid Build Coastguard Worker {
137*b9df5ad1SAndroid Build Coastguard Worker // maximum value of frameCount * frameSize is INT32_MAX (2^31 - 1), not 2^31, because we need to
138*b9df5ad1SAndroid Build Coastguard Worker // be able to distinguish successful and error return values from read and write.
139*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
140*b9df5ad1SAndroid Build Coastguard Worker frameCount > ((uint32_t) INT32_MAX) / frameSize);
141*b9df5ad1SAndroid Build Coastguard Worker }
142*b9df5ad1SAndroid Build Coastguard Worker
audio_utils_fifo(uint32_t frameCount,uint32_t frameSize,void * buffer,bool throttlesWriter,audio_utils_fifo_sync sync)143*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
144*b9df5ad1SAndroid Build Coastguard Worker bool throttlesWriter, audio_utils_fifo_sync sync) :
145*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
146*b9df5ad1SAndroid Build Coastguard Worker throttlesWriter ? &mSingleProcessSharedFront : NULL)
147*b9df5ad1SAndroid Build Coastguard Worker {
148*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(sync == AUDIO_UTILS_FIFO_SYNC_SHARED);
149*b9df5ad1SAndroid Build Coastguard Worker }
150*b9df5ad1SAndroid Build Coastguard Worker
~audio_utils_fifo()151*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo::~audio_utils_fifo()
152*b9df5ad1SAndroid Build Coastguard Worker {
153*b9df5ad1SAndroid Build Coastguard Worker }
154*b9df5ad1SAndroid Build Coastguard Worker
155*b9df5ad1SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
156*b9df5ad1SAndroid Build Coastguard Worker
audio_utils_fifo_provider(audio_utils_fifo & fifo)157*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
158*b9df5ad1SAndroid Build Coastguard Worker mFifo(fifo), mObtained(0), mTotalReleased(0)
159*b9df5ad1SAndroid Build Coastguard Worker {
160*b9df5ad1SAndroid Build Coastguard Worker }
161*b9df5ad1SAndroid Build Coastguard Worker
~audio_utils_fifo_provider()162*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_provider::~audio_utils_fifo_provider()
163*b9df5ad1SAndroid Build Coastguard Worker {
164*b9df5ad1SAndroid Build Coastguard Worker }
165*b9df5ad1SAndroid Build Coastguard Worker
166*b9df5ad1SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
167*b9df5ad1SAndroid Build Coastguard Worker
audio_utils_fifo_writer(audio_utils_fifo & fifo)168*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
169*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_provider(fifo), mLocalRear(0),
170*b9df5ad1SAndroid Build Coastguard Worker mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
171*b9df5ad1SAndroid Build Coastguard Worker mIsArmed(true), // because initial fill level of zero is < mArmLevel
172*b9df5ad1SAndroid Build Coastguard Worker mEffectiveFrames(fifo.mFrameCount)
173*b9df5ad1SAndroid Build Coastguard Worker {
174*b9df5ad1SAndroid Build Coastguard Worker }
175*b9df5ad1SAndroid Build Coastguard Worker
~audio_utils_fifo_writer()176*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_writer::~audio_utils_fifo_writer()
177*b9df5ad1SAndroid Build Coastguard Worker {
178*b9df5ad1SAndroid Build Coastguard Worker }
179*b9df5ad1SAndroid Build Coastguard Worker
write(const void * buffer,size_t count,const struct timespec * timeout)180*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
181*b9df5ad1SAndroid Build Coastguard Worker const struct timespec *timeout)
182*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
183*b9df5ad1SAndroid Build Coastguard Worker {
184*b9df5ad1SAndroid Build Coastguard Worker audio_utils_iovec iovec[2];
185*b9df5ad1SAndroid Build Coastguard Worker ssize_t availToWrite = obtain(iovec, count, timeout);
186*b9df5ad1SAndroid Build Coastguard Worker if (availToWrite > 0) {
187*b9df5ad1SAndroid Build Coastguard Worker memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
188*b9df5ad1SAndroid Build Coastguard Worker iovec[0].mLength * mFifo.mFrameSize);
189*b9df5ad1SAndroid Build Coastguard Worker if (iovec[1].mLength > 0) {
190*b9df5ad1SAndroid Build Coastguard Worker memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
191*b9df5ad1SAndroid Build Coastguard Worker (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
192*b9df5ad1SAndroid Build Coastguard Worker iovec[1].mLength * mFifo.mFrameSize);
193*b9df5ad1SAndroid Build Coastguard Worker }
194*b9df5ad1SAndroid Build Coastguard Worker release(availToWrite);
195*b9df5ad1SAndroid Build Coastguard Worker }
196*b9df5ad1SAndroid Build Coastguard Worker return availToWrite;
197*b9df5ad1SAndroid Build Coastguard Worker }
198*b9df5ad1SAndroid Build Coastguard Worker
199*b9df5ad1SAndroid Build Coastguard Worker // iovec == NULL is not part of the public API, but internally it means don't set mObtained
obtain(audio_utils_iovec iovec[2],size_t count,const struct timespec * timeout)200*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
201*b9df5ad1SAndroid Build Coastguard Worker const struct timespec *timeout)
202*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
203*b9df5ad1SAndroid Build Coastguard Worker {
204*b9df5ad1SAndroid Build Coastguard Worker int err = 0;
205*b9df5ad1SAndroid Build Coastguard Worker size_t availToWrite;
206*b9df5ad1SAndroid Build Coastguard Worker if (mFifo.mThrottleFront != NULL) {
207*b9df5ad1SAndroid Build Coastguard Worker int retries = kRetries;
208*b9df5ad1SAndroid Build Coastguard Worker for (;;) {
209*b9df5ad1SAndroid Build Coastguard Worker uint32_t front = mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
210*b9df5ad1SAndroid Build Coastguard Worker mFifo.mThrottleFront->loadSingleThreaded() :
211*b9df5ad1SAndroid Build Coastguard Worker mFifo.mThrottleFront->loadAcquire();
212*b9df5ad1SAndroid Build Coastguard Worker // returns -EIO if mIsShutdown
213*b9df5ad1SAndroid Build Coastguard Worker int32_t filled = mFifo.diff(mLocalRear, front);
214*b9df5ad1SAndroid Build Coastguard Worker if (filled < 0) {
215*b9df5ad1SAndroid Build Coastguard Worker // on error, return an empty slice
216*b9df5ad1SAndroid Build Coastguard Worker err = filled;
217*b9df5ad1SAndroid Build Coastguard Worker availToWrite = 0;
218*b9df5ad1SAndroid Build Coastguard Worker break;
219*b9df5ad1SAndroid Build Coastguard Worker }
220*b9df5ad1SAndroid Build Coastguard Worker availToWrite = mEffectiveFrames > (uint32_t) filled ?
221*b9df5ad1SAndroid Build Coastguard Worker mEffectiveFrames - (uint32_t) filled : 0;
222*b9df5ad1SAndroid Build Coastguard Worker // TODO pull out "count == 0"
223*b9df5ad1SAndroid Build Coastguard Worker if (count == 0 || availToWrite > 0 || timeout == NULL ||
224*b9df5ad1SAndroid Build Coastguard Worker (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
225*b9df5ad1SAndroid Build Coastguard Worker break;
226*b9df5ad1SAndroid Build Coastguard Worker }
227*b9df5ad1SAndroid Build Coastguard Worker // TODO add comments
228*b9df5ad1SAndroid Build Coastguard Worker // TODO abstract out switch and replace by general sync object
229*b9df5ad1SAndroid Build Coastguard Worker // the high level code (synchronization, sleep, futex, iovec) should be completely
230*b9df5ad1SAndroid Build Coastguard Worker // separate from the low level code (indexes, available, masking).
231*b9df5ad1SAndroid Build Coastguard Worker int op = FUTEX_WAIT;
232*b9df5ad1SAndroid Build Coastguard Worker switch (mFifo.mThrottleFrontSync) {
233*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
234*b9df5ad1SAndroid Build Coastguard Worker err = -ENOTSUP;
235*b9df5ad1SAndroid Build Coastguard Worker break;
236*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SLEEP:
237*b9df5ad1SAndroid Build Coastguard Worker err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
238*b9df5ad1SAndroid Build Coastguard Worker NULL /*remain*/);
239*b9df5ad1SAndroid Build Coastguard Worker if (err < 0) {
240*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
241*b9df5ad1SAndroid Build Coastguard Worker err = -errno;
242*b9df5ad1SAndroid Build Coastguard Worker } else {
243*b9df5ad1SAndroid Build Coastguard Worker err = -ETIMEDOUT;
244*b9df5ad1SAndroid Build Coastguard Worker }
245*b9df5ad1SAndroid Build Coastguard Worker break;
246*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
247*b9df5ad1SAndroid Build Coastguard Worker op = FUTEX_WAIT_PRIVATE;
248*b9df5ad1SAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
249*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SHARED:
250*b9df5ad1SAndroid Build Coastguard Worker if (timeout->tv_sec == LONG_MAX) {
251*b9df5ad1SAndroid Build Coastguard Worker timeout = NULL;
252*b9df5ad1SAndroid Build Coastguard Worker }
253*b9df5ad1SAndroid Build Coastguard Worker err = mFifo.mThrottleFront->wait(op, front, timeout);
254*b9df5ad1SAndroid Build Coastguard Worker if (err < 0) {
255*b9df5ad1SAndroid Build Coastguard Worker switch (errno) {
256*b9df5ad1SAndroid Build Coastguard Worker case EWOULDBLOCK:
257*b9df5ad1SAndroid Build Coastguard Worker // Benign race condition with partner: mFifo.mThrottleFront->mIndex
258*b9df5ad1SAndroid Build Coastguard Worker // changed value between the earlier atomic_load_explicit() and sys_futex().
259*b9df5ad1SAndroid Build Coastguard Worker // Try to load index again, but give up if we are unable to converge.
260*b9df5ad1SAndroid Build Coastguard Worker if (retries-- > 0) {
261*b9df5ad1SAndroid Build Coastguard Worker // bypass the "timeout = NULL;" below
262*b9df5ad1SAndroid Build Coastguard Worker continue;
263*b9df5ad1SAndroid Build Coastguard Worker }
264*b9df5ad1SAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
265*b9df5ad1SAndroid Build Coastguard Worker case EINTR:
266*b9df5ad1SAndroid Build Coastguard Worker case ETIMEDOUT:
267*b9df5ad1SAndroid Build Coastguard Worker err = -errno;
268*b9df5ad1SAndroid Build Coastguard Worker break;
269*b9df5ad1SAndroid Build Coastguard Worker default:
270*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
271*b9df5ad1SAndroid Build Coastguard Worker break;
272*b9df5ad1SAndroid Build Coastguard Worker }
273*b9df5ad1SAndroid Build Coastguard Worker }
274*b9df5ad1SAndroid Build Coastguard Worker break;
275*b9df5ad1SAndroid Build Coastguard Worker default:
276*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
277*b9df5ad1SAndroid Build Coastguard Worker break;
278*b9df5ad1SAndroid Build Coastguard Worker }
279*b9df5ad1SAndroid Build Coastguard Worker timeout = NULL;
280*b9df5ad1SAndroid Build Coastguard Worker }
281*b9df5ad1SAndroid Build Coastguard Worker } else {
282*b9df5ad1SAndroid Build Coastguard Worker if (mFifo.mIsShutdown) {
283*b9df5ad1SAndroid Build Coastguard Worker err = -EIO;
284*b9df5ad1SAndroid Build Coastguard Worker availToWrite = 0;
285*b9df5ad1SAndroid Build Coastguard Worker } else {
286*b9df5ad1SAndroid Build Coastguard Worker availToWrite = mEffectiveFrames;
287*b9df5ad1SAndroid Build Coastguard Worker }
288*b9df5ad1SAndroid Build Coastguard Worker }
289*b9df5ad1SAndroid Build Coastguard Worker if (availToWrite > count) {
290*b9df5ad1SAndroid Build Coastguard Worker availToWrite = count;
291*b9df5ad1SAndroid Build Coastguard Worker }
292*b9df5ad1SAndroid Build Coastguard Worker uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
293*b9df5ad1SAndroid Build Coastguard Worker size_t part1 = mFifo.mFrameCount - rearOffset;
294*b9df5ad1SAndroid Build Coastguard Worker if (part1 > availToWrite) {
295*b9df5ad1SAndroid Build Coastguard Worker part1 = availToWrite;
296*b9df5ad1SAndroid Build Coastguard Worker }
297*b9df5ad1SAndroid Build Coastguard Worker size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
298*b9df5ad1SAndroid Build Coastguard Worker // return slice
299*b9df5ad1SAndroid Build Coastguard Worker if (iovec != NULL) {
300*b9df5ad1SAndroid Build Coastguard Worker iovec[0].mOffset = rearOffset;
301*b9df5ad1SAndroid Build Coastguard Worker iovec[0].mLength = part1;
302*b9df5ad1SAndroid Build Coastguard Worker iovec[1].mOffset = 0;
303*b9df5ad1SAndroid Build Coastguard Worker iovec[1].mLength = part2;
304*b9df5ad1SAndroid Build Coastguard Worker mObtained = availToWrite;
305*b9df5ad1SAndroid Build Coastguard Worker }
306*b9df5ad1SAndroid Build Coastguard Worker return availToWrite > 0 ? availToWrite : err;
307*b9df5ad1SAndroid Build Coastguard Worker }
308*b9df5ad1SAndroid Build Coastguard Worker
release(size_t count)309*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_writer::release(size_t count)
310*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
311*b9df5ad1SAndroid Build Coastguard Worker {
312*b9df5ad1SAndroid Build Coastguard Worker // no need to do an early check for mIsShutdown, because the extra code executed is harmless
313*b9df5ad1SAndroid Build Coastguard Worker if (count > 0) {
314*b9df5ad1SAndroid Build Coastguard Worker if (count > mObtained) {
315*b9df5ad1SAndroid Build Coastguard Worker ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
316*b9df5ad1SAndroid Build Coastguard Worker mFifo.shutdown();
317*b9df5ad1SAndroid Build Coastguard Worker return;
318*b9df5ad1SAndroid Build Coastguard Worker }
319*b9df5ad1SAndroid Build Coastguard Worker if (mFifo.mThrottleFront != NULL) {
320*b9df5ad1SAndroid Build Coastguard Worker uint32_t front = mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
321*b9df5ad1SAndroid Build Coastguard Worker mFifo.mThrottleFront->loadSingleThreaded() :
322*b9df5ad1SAndroid Build Coastguard Worker mFifo.mThrottleFront->loadAcquire();
323*b9df5ad1SAndroid Build Coastguard Worker // returns -EIO if mIsShutdown
324*b9df5ad1SAndroid Build Coastguard Worker int32_t filled = mFifo.diff(mLocalRear, front);
325*b9df5ad1SAndroid Build Coastguard Worker mLocalRear = mFifo.sum(mLocalRear, count);
326*b9df5ad1SAndroid Build Coastguard Worker if (mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) {
327*b9df5ad1SAndroid Build Coastguard Worker mFifo.mWriterRear.storeSingleThreaded(mLocalRear);
328*b9df5ad1SAndroid Build Coastguard Worker } else {
329*b9df5ad1SAndroid Build Coastguard Worker mFifo.mWriterRear.storeRelease(mLocalRear);
330*b9df5ad1SAndroid Build Coastguard Worker }
331*b9df5ad1SAndroid Build Coastguard Worker // TODO add comments
332*b9df5ad1SAndroid Build Coastguard Worker int op = FUTEX_WAKE;
333*b9df5ad1SAndroid Build Coastguard Worker switch (mFifo.mWriterRearSync) {
334*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
335*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SLEEP:
336*b9df5ad1SAndroid Build Coastguard Worker break;
337*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
338*b9df5ad1SAndroid Build Coastguard Worker op = FUTEX_WAKE_PRIVATE;
339*b9df5ad1SAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
340*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SHARED:
341*b9df5ad1SAndroid Build Coastguard Worker if (filled >= 0) {
342*b9df5ad1SAndroid Build Coastguard Worker if ((uint32_t) filled < mArmLevel) {
343*b9df5ad1SAndroid Build Coastguard Worker mIsArmed = true;
344*b9df5ad1SAndroid Build Coastguard Worker }
345*b9df5ad1SAndroid Build Coastguard Worker if (mIsArmed && filled + count > mTriggerLevel) {
346*b9df5ad1SAndroid Build Coastguard Worker int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
347*b9df5ad1SAndroid Build Coastguard Worker // err is number of processes woken up
348*b9df5ad1SAndroid Build Coastguard Worker if (err < 0) {
349*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
350*b9df5ad1SAndroid Build Coastguard Worker __func__, err, errno);
351*b9df5ad1SAndroid Build Coastguard Worker }
352*b9df5ad1SAndroid Build Coastguard Worker mIsArmed = false;
353*b9df5ad1SAndroid Build Coastguard Worker }
354*b9df5ad1SAndroid Build Coastguard Worker }
355*b9df5ad1SAndroid Build Coastguard Worker break;
356*b9df5ad1SAndroid Build Coastguard Worker default:
357*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
358*b9df5ad1SAndroid Build Coastguard Worker break;
359*b9df5ad1SAndroid Build Coastguard Worker }
360*b9df5ad1SAndroid Build Coastguard Worker } else {
361*b9df5ad1SAndroid Build Coastguard Worker mLocalRear = mFifo.sum(mLocalRear, count);
362*b9df5ad1SAndroid Build Coastguard Worker if (mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) {
363*b9df5ad1SAndroid Build Coastguard Worker mFifo.mWriterRear.storeSingleThreaded(mLocalRear);
364*b9df5ad1SAndroid Build Coastguard Worker } else {
365*b9df5ad1SAndroid Build Coastguard Worker mFifo.mWriterRear.storeRelease(mLocalRear);
366*b9df5ad1SAndroid Build Coastguard Worker }
367*b9df5ad1SAndroid Build Coastguard Worker }
368*b9df5ad1SAndroid Build Coastguard Worker mObtained -= count;
369*b9df5ad1SAndroid Build Coastguard Worker mTotalReleased += count;
370*b9df5ad1SAndroid Build Coastguard Worker }
371*b9df5ad1SAndroid Build Coastguard Worker }
372*b9df5ad1SAndroid Build Coastguard Worker
available()373*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_writer::available()
374*b9df5ad1SAndroid Build Coastguard Worker {
375*b9df5ad1SAndroid Build Coastguard Worker // iovec == NULL is not part of the public API, but internally it means don't set mObtained
376*b9df5ad1SAndroid Build Coastguard Worker return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
377*b9df5ad1SAndroid Build Coastguard Worker }
378*b9df5ad1SAndroid Build Coastguard Worker
resize(uint32_t frameCount)379*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_writer::resize(uint32_t frameCount)
380*b9df5ad1SAndroid Build Coastguard Worker {
381*b9df5ad1SAndroid Build Coastguard Worker // cap to range [0, mFifo.mFrameCount]
382*b9df5ad1SAndroid Build Coastguard Worker if (frameCount > mFifo.mFrameCount) {
383*b9df5ad1SAndroid Build Coastguard Worker frameCount = mFifo.mFrameCount;
384*b9df5ad1SAndroid Build Coastguard Worker }
385*b9df5ad1SAndroid Build Coastguard Worker // if we reduce the effective frame count, update hysteresis points to be within the new range
386*b9df5ad1SAndroid Build Coastguard Worker if (frameCount < mEffectiveFrames) {
387*b9df5ad1SAndroid Build Coastguard Worker if (mArmLevel > frameCount) {
388*b9df5ad1SAndroid Build Coastguard Worker mArmLevel = frameCount;
389*b9df5ad1SAndroid Build Coastguard Worker }
390*b9df5ad1SAndroid Build Coastguard Worker if (mTriggerLevel > frameCount) {
391*b9df5ad1SAndroid Build Coastguard Worker mTriggerLevel = frameCount;
392*b9df5ad1SAndroid Build Coastguard Worker }
393*b9df5ad1SAndroid Build Coastguard Worker }
394*b9df5ad1SAndroid Build Coastguard Worker mEffectiveFrames = frameCount;
395*b9df5ad1SAndroid Build Coastguard Worker }
396*b9df5ad1SAndroid Build Coastguard Worker
size() const397*b9df5ad1SAndroid Build Coastguard Worker uint32_t audio_utils_fifo_writer::size() const
398*b9df5ad1SAndroid Build Coastguard Worker {
399*b9df5ad1SAndroid Build Coastguard Worker return mEffectiveFrames;
400*b9df5ad1SAndroid Build Coastguard Worker }
401*b9df5ad1SAndroid Build Coastguard Worker
setHysteresis(uint32_t lowLevelArm,uint32_t highLevelTrigger)402*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
403*b9df5ad1SAndroid Build Coastguard Worker {
404*b9df5ad1SAndroid Build Coastguard Worker // cap to range [0, mEffectiveFrames]
405*b9df5ad1SAndroid Build Coastguard Worker if (lowLevelArm > mEffectiveFrames) {
406*b9df5ad1SAndroid Build Coastguard Worker lowLevelArm = mEffectiveFrames;
407*b9df5ad1SAndroid Build Coastguard Worker }
408*b9df5ad1SAndroid Build Coastguard Worker if (highLevelTrigger > mEffectiveFrames) {
409*b9df5ad1SAndroid Build Coastguard Worker highLevelTrigger = mEffectiveFrames;
410*b9df5ad1SAndroid Build Coastguard Worker }
411*b9df5ad1SAndroid Build Coastguard Worker // TODO this is overly conservative; it would be better to arm based on actual fill level
412*b9df5ad1SAndroid Build Coastguard Worker if (lowLevelArm > mArmLevel) {
413*b9df5ad1SAndroid Build Coastguard Worker mIsArmed = true;
414*b9df5ad1SAndroid Build Coastguard Worker }
415*b9df5ad1SAndroid Build Coastguard Worker mArmLevel = lowLevelArm;
416*b9df5ad1SAndroid Build Coastguard Worker mTriggerLevel = highLevelTrigger;
417*b9df5ad1SAndroid Build Coastguard Worker }
418*b9df5ad1SAndroid Build Coastguard Worker
getHysteresis(uint32_t * armLevel,uint32_t * triggerLevel) const419*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
420*b9df5ad1SAndroid Build Coastguard Worker {
421*b9df5ad1SAndroid Build Coastguard Worker *armLevel = mArmLevel;
422*b9df5ad1SAndroid Build Coastguard Worker *triggerLevel = mTriggerLevel;
423*b9df5ad1SAndroid Build Coastguard Worker }
424*b9df5ad1SAndroid Build Coastguard Worker
425*b9df5ad1SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
426*b9df5ad1SAndroid Build Coastguard Worker
audio_utils_fifo_reader(audio_utils_fifo & fifo,bool throttlesWriter,bool flush)427*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter,
428*b9df5ad1SAndroid Build Coastguard Worker bool flush) :
429*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_provider(fifo),
430*b9df5ad1SAndroid Build Coastguard Worker
431*b9df5ad1SAndroid Build Coastguard Worker // If we throttle the writer, then initialize our front index to zero so that we see all data
432*b9df5ad1SAndroid Build Coastguard Worker // currently in the buffer.
433*b9df5ad1SAndroid Build Coastguard Worker // Otherwise, ignore everything currently in the buffer by initializing our front index to the
434*b9df5ad1SAndroid Build Coastguard Worker // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case
435*b9df5ad1SAndroid Build Coastguard Worker // where reader starts out more than one buffer behind writer. The initial catch-up does not
436*b9df5ad1SAndroid Build Coastguard Worker // contribute towards the totalLost, totalFlushed, or totalReleased counters.
437*b9df5ad1SAndroid Build Coastguard Worker mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadAcquire()),
438*b9df5ad1SAndroid Build Coastguard Worker
439*b9df5ad1SAndroid Build Coastguard Worker mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
440*b9df5ad1SAndroid Build Coastguard Worker mFlush(flush),
441*b9df5ad1SAndroid Build Coastguard Worker mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
442*b9df5ad1SAndroid Build Coastguard Worker mIsArmed(true), // because initial fill level of zero is > mArmLevel
443*b9df5ad1SAndroid Build Coastguard Worker mTotalLost(0), mTotalFlushed(0)
444*b9df5ad1SAndroid Build Coastguard Worker {
445*b9df5ad1SAndroid Build Coastguard Worker }
446*b9df5ad1SAndroid Build Coastguard Worker
~audio_utils_fifo_reader()447*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_reader::~audio_utils_fifo_reader()
448*b9df5ad1SAndroid Build Coastguard Worker {
449*b9df5ad1SAndroid Build Coastguard Worker // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
450*b9df5ad1SAndroid Build Coastguard Worker }
451*b9df5ad1SAndroid Build Coastguard Worker
read(void * buffer,size_t count,const struct timespec * timeout,size_t * lost)452*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
453*b9df5ad1SAndroid Build Coastguard Worker size_t *lost)
454*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
455*b9df5ad1SAndroid Build Coastguard Worker {
456*b9df5ad1SAndroid Build Coastguard Worker audio_utils_iovec iovec[2];
457*b9df5ad1SAndroid Build Coastguard Worker ssize_t availToRead = obtain(iovec, count, timeout, lost);
458*b9df5ad1SAndroid Build Coastguard Worker if (availToRead > 0) {
459*b9df5ad1SAndroid Build Coastguard Worker memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
460*b9df5ad1SAndroid Build Coastguard Worker iovec[0].mLength * mFifo.mFrameSize);
461*b9df5ad1SAndroid Build Coastguard Worker if (iovec[1].mLength > 0) {
462*b9df5ad1SAndroid Build Coastguard Worker memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
463*b9df5ad1SAndroid Build Coastguard Worker (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
464*b9df5ad1SAndroid Build Coastguard Worker iovec[1].mLength * mFifo.mFrameSize);
465*b9df5ad1SAndroid Build Coastguard Worker }
466*b9df5ad1SAndroid Build Coastguard Worker release(availToRead);
467*b9df5ad1SAndroid Build Coastguard Worker }
468*b9df5ad1SAndroid Build Coastguard Worker return availToRead;
469*b9df5ad1SAndroid Build Coastguard Worker }
470*b9df5ad1SAndroid Build Coastguard Worker
obtain(audio_utils_iovec iovec[2],size_t count,const struct timespec * timeout)471*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
472*b9df5ad1SAndroid Build Coastguard Worker const struct timespec *timeout)
473*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
474*b9df5ad1SAndroid Build Coastguard Worker {
475*b9df5ad1SAndroid Build Coastguard Worker return obtain(iovec, count, timeout, NULL /*lost*/);
476*b9df5ad1SAndroid Build Coastguard Worker }
477*b9df5ad1SAndroid Build Coastguard Worker
release(size_t count)478*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_reader::release(size_t count)
479*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
480*b9df5ad1SAndroid Build Coastguard Worker {
481*b9df5ad1SAndroid Build Coastguard Worker // no need to do an early check for mIsShutdown, because the extra code executed is harmless
482*b9df5ad1SAndroid Build Coastguard Worker if (count > 0) {
483*b9df5ad1SAndroid Build Coastguard Worker if (count > mObtained) {
484*b9df5ad1SAndroid Build Coastguard Worker ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
485*b9df5ad1SAndroid Build Coastguard Worker mFifo.shutdown();
486*b9df5ad1SAndroid Build Coastguard Worker return;
487*b9df5ad1SAndroid Build Coastguard Worker }
488*b9df5ad1SAndroid Build Coastguard Worker if (mThrottleFront != NULL) {
489*b9df5ad1SAndroid Build Coastguard Worker uint32_t rear = mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
490*b9df5ad1SAndroid Build Coastguard Worker mFifo.mWriterRear.loadSingleThreaded() : mFifo.mWriterRear.loadAcquire();
491*b9df5ad1SAndroid Build Coastguard Worker // returns -EIO if mIsShutdown
492*b9df5ad1SAndroid Build Coastguard Worker int32_t filled = mFifo.diff(rear, mLocalFront);
493*b9df5ad1SAndroid Build Coastguard Worker mLocalFront = mFifo.sum(mLocalFront, count);
494*b9df5ad1SAndroid Build Coastguard Worker if (mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) {
495*b9df5ad1SAndroid Build Coastguard Worker mThrottleFront->storeSingleThreaded(mLocalFront);
496*b9df5ad1SAndroid Build Coastguard Worker } else {
497*b9df5ad1SAndroid Build Coastguard Worker mThrottleFront->storeRelease(mLocalFront);
498*b9df5ad1SAndroid Build Coastguard Worker }
499*b9df5ad1SAndroid Build Coastguard Worker // TODO add comments
500*b9df5ad1SAndroid Build Coastguard Worker int op = FUTEX_WAKE;
501*b9df5ad1SAndroid Build Coastguard Worker switch (mFifo.mThrottleFrontSync) {
502*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
503*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SLEEP:
504*b9df5ad1SAndroid Build Coastguard Worker break;
505*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
506*b9df5ad1SAndroid Build Coastguard Worker op = FUTEX_WAKE_PRIVATE;
507*b9df5ad1SAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
508*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SHARED:
509*b9df5ad1SAndroid Build Coastguard Worker if (filled >= 0) {
510*b9df5ad1SAndroid Build Coastguard Worker if (filled > mArmLevel) {
511*b9df5ad1SAndroid Build Coastguard Worker mIsArmed = true;
512*b9df5ad1SAndroid Build Coastguard Worker }
513*b9df5ad1SAndroid Build Coastguard Worker if (mIsArmed && filled - count < mTriggerLevel) {
514*b9df5ad1SAndroid Build Coastguard Worker int err = mThrottleFront->wake(op, 1 /*waiters*/);
515*b9df5ad1SAndroid Build Coastguard Worker // err is number of processes woken up
516*b9df5ad1SAndroid Build Coastguard Worker if (err < 0 || err > 1) {
517*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
518*b9df5ad1SAndroid Build Coastguard Worker __func__, err, errno);
519*b9df5ad1SAndroid Build Coastguard Worker }
520*b9df5ad1SAndroid Build Coastguard Worker mIsArmed = false;
521*b9df5ad1SAndroid Build Coastguard Worker }
522*b9df5ad1SAndroid Build Coastguard Worker }
523*b9df5ad1SAndroid Build Coastguard Worker break;
524*b9df5ad1SAndroid Build Coastguard Worker default:
525*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
526*b9df5ad1SAndroid Build Coastguard Worker break;
527*b9df5ad1SAndroid Build Coastguard Worker }
528*b9df5ad1SAndroid Build Coastguard Worker } else {
529*b9df5ad1SAndroid Build Coastguard Worker mLocalFront = mFifo.sum(mLocalFront, count);
530*b9df5ad1SAndroid Build Coastguard Worker }
531*b9df5ad1SAndroid Build Coastguard Worker mObtained -= count;
532*b9df5ad1SAndroid Build Coastguard Worker mTotalReleased += count;
533*b9df5ad1SAndroid Build Coastguard Worker }
534*b9df5ad1SAndroid Build Coastguard Worker }
535*b9df5ad1SAndroid Build Coastguard Worker
536*b9df5ad1SAndroid Build Coastguard Worker // iovec == NULL is not part of the public API, but internally it means don't set mObtained
obtain(audio_utils_iovec iovec[2],size_t count,const struct timespec * timeout,size_t * lost)537*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
538*b9df5ad1SAndroid Build Coastguard Worker const struct timespec *timeout, size_t *lost)
539*b9df5ad1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
540*b9df5ad1SAndroid Build Coastguard Worker {
541*b9df5ad1SAndroid Build Coastguard Worker int err = 0;
542*b9df5ad1SAndroid Build Coastguard Worker int retries = kRetries;
543*b9df5ad1SAndroid Build Coastguard Worker uint32_t rear;
544*b9df5ad1SAndroid Build Coastguard Worker for (;;) {
545*b9df5ad1SAndroid Build Coastguard Worker rear = mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ?
546*b9df5ad1SAndroid Build Coastguard Worker mFifo.mWriterRear.loadSingleThreaded() : mFifo.mWriterRear.loadAcquire();
547*b9df5ad1SAndroid Build Coastguard Worker // TODO pull out "count == 0"
548*b9df5ad1SAndroid Build Coastguard Worker if (count == 0 || rear != mLocalFront || timeout == NULL ||
549*b9df5ad1SAndroid Build Coastguard Worker (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
550*b9df5ad1SAndroid Build Coastguard Worker break;
551*b9df5ad1SAndroid Build Coastguard Worker }
552*b9df5ad1SAndroid Build Coastguard Worker // TODO add comments
553*b9df5ad1SAndroid Build Coastguard Worker int op = FUTEX_WAIT;
554*b9df5ad1SAndroid Build Coastguard Worker switch (mFifo.mWriterRearSync) {
555*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED:
556*b9df5ad1SAndroid Build Coastguard Worker err = -ENOTSUP;
557*b9df5ad1SAndroid Build Coastguard Worker break;
558*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SLEEP:
559*b9df5ad1SAndroid Build Coastguard Worker err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
560*b9df5ad1SAndroid Build Coastguard Worker NULL /*remain*/);
561*b9df5ad1SAndroid Build Coastguard Worker if (err < 0) {
562*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
563*b9df5ad1SAndroid Build Coastguard Worker err = -errno;
564*b9df5ad1SAndroid Build Coastguard Worker } else {
565*b9df5ad1SAndroid Build Coastguard Worker err = -ETIMEDOUT;
566*b9df5ad1SAndroid Build Coastguard Worker }
567*b9df5ad1SAndroid Build Coastguard Worker break;
568*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
569*b9df5ad1SAndroid Build Coastguard Worker op = FUTEX_WAIT_PRIVATE;
570*b9df5ad1SAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
571*b9df5ad1SAndroid Build Coastguard Worker case AUDIO_UTILS_FIFO_SYNC_SHARED:
572*b9df5ad1SAndroid Build Coastguard Worker if (timeout->tv_sec == LONG_MAX) {
573*b9df5ad1SAndroid Build Coastguard Worker timeout = NULL;
574*b9df5ad1SAndroid Build Coastguard Worker }
575*b9df5ad1SAndroid Build Coastguard Worker err = mFifo.mWriterRear.wait(op, rear, timeout);
576*b9df5ad1SAndroid Build Coastguard Worker if (err < 0) {
577*b9df5ad1SAndroid Build Coastguard Worker switch (errno) {
578*b9df5ad1SAndroid Build Coastguard Worker case EWOULDBLOCK:
579*b9df5ad1SAndroid Build Coastguard Worker // Benign race condition with partner: mFifo.mWriterRear->mIndex
580*b9df5ad1SAndroid Build Coastguard Worker // changed value between the earlier atomic_load_explicit() and sys_futex().
581*b9df5ad1SAndroid Build Coastguard Worker // Try to load index again, but give up if we are unable to converge.
582*b9df5ad1SAndroid Build Coastguard Worker if (retries-- > 0) {
583*b9df5ad1SAndroid Build Coastguard Worker // bypass the "timeout = NULL;" below
584*b9df5ad1SAndroid Build Coastguard Worker continue;
585*b9df5ad1SAndroid Build Coastguard Worker }
586*b9df5ad1SAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
587*b9df5ad1SAndroid Build Coastguard Worker case EINTR:
588*b9df5ad1SAndroid Build Coastguard Worker case ETIMEDOUT:
589*b9df5ad1SAndroid Build Coastguard Worker err = -errno;
590*b9df5ad1SAndroid Build Coastguard Worker break;
591*b9df5ad1SAndroid Build Coastguard Worker default:
592*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
593*b9df5ad1SAndroid Build Coastguard Worker break;
594*b9df5ad1SAndroid Build Coastguard Worker }
595*b9df5ad1SAndroid Build Coastguard Worker }
596*b9df5ad1SAndroid Build Coastguard Worker break;
597*b9df5ad1SAndroid Build Coastguard Worker default:
598*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
599*b9df5ad1SAndroid Build Coastguard Worker break;
600*b9df5ad1SAndroid Build Coastguard Worker }
601*b9df5ad1SAndroid Build Coastguard Worker timeout = NULL;
602*b9df5ad1SAndroid Build Coastguard Worker }
603*b9df5ad1SAndroid Build Coastguard Worker size_t ourLost;
604*b9df5ad1SAndroid Build Coastguard Worker if (lost == NULL) {
605*b9df5ad1SAndroid Build Coastguard Worker lost = &ourLost;
606*b9df5ad1SAndroid Build Coastguard Worker }
607*b9df5ad1SAndroid Build Coastguard Worker // returns -EIO if mIsShutdown
608*b9df5ad1SAndroid Build Coastguard Worker int32_t filled = mFifo.diff(rear, mLocalFront, lost, mFlush);
609*b9df5ad1SAndroid Build Coastguard Worker mTotalLost += *lost;
610*b9df5ad1SAndroid Build Coastguard Worker mTotalReleased += *lost;
611*b9df5ad1SAndroid Build Coastguard Worker if (filled < 0) {
612*b9df5ad1SAndroid Build Coastguard Worker if (filled == -EOVERFLOW) {
613*b9df5ad1SAndroid Build Coastguard Worker // catch up with writer, but preserve the still valid frames in buffer
614*b9df5ad1SAndroid Build Coastguard Worker mLocalFront = rear - (mFlush ? 0 : mFifo.mFrameCountP2 /*sic*/);
615*b9df5ad1SAndroid Build Coastguard Worker }
616*b9df5ad1SAndroid Build Coastguard Worker // on error, return an empty slice
617*b9df5ad1SAndroid Build Coastguard Worker err = filled;
618*b9df5ad1SAndroid Build Coastguard Worker filled = 0;
619*b9df5ad1SAndroid Build Coastguard Worker }
620*b9df5ad1SAndroid Build Coastguard Worker size_t availToRead = (size_t) filled;
621*b9df5ad1SAndroid Build Coastguard Worker if (availToRead > count) {
622*b9df5ad1SAndroid Build Coastguard Worker availToRead = count;
623*b9df5ad1SAndroid Build Coastguard Worker }
624*b9df5ad1SAndroid Build Coastguard Worker uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
625*b9df5ad1SAndroid Build Coastguard Worker size_t part1 = mFifo.mFrameCount - frontOffset;
626*b9df5ad1SAndroid Build Coastguard Worker if (part1 > availToRead) {
627*b9df5ad1SAndroid Build Coastguard Worker part1 = availToRead;
628*b9df5ad1SAndroid Build Coastguard Worker }
629*b9df5ad1SAndroid Build Coastguard Worker size_t part2 = part1 > 0 ? availToRead - part1 : 0;
630*b9df5ad1SAndroid Build Coastguard Worker // return slice
631*b9df5ad1SAndroid Build Coastguard Worker if (iovec != NULL) {
632*b9df5ad1SAndroid Build Coastguard Worker iovec[0].mOffset = frontOffset;
633*b9df5ad1SAndroid Build Coastguard Worker iovec[0].mLength = part1;
634*b9df5ad1SAndroid Build Coastguard Worker iovec[1].mOffset = 0;
635*b9df5ad1SAndroid Build Coastguard Worker iovec[1].mLength = part2;
636*b9df5ad1SAndroid Build Coastguard Worker mObtained = availToRead;
637*b9df5ad1SAndroid Build Coastguard Worker }
638*b9df5ad1SAndroid Build Coastguard Worker return availToRead > 0 ? availToRead : err;
639*b9df5ad1SAndroid Build Coastguard Worker }
640*b9df5ad1SAndroid Build Coastguard Worker
available()641*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_reader::available()
642*b9df5ad1SAndroid Build Coastguard Worker {
643*b9df5ad1SAndroid Build Coastguard Worker return available(NULL /*lost*/);
644*b9df5ad1SAndroid Build Coastguard Worker }
645*b9df5ad1SAndroid Build Coastguard Worker
available(size_t * lost)646*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_reader::available(size_t *lost)
647*b9df5ad1SAndroid Build Coastguard Worker {
648*b9df5ad1SAndroid Build Coastguard Worker // iovec == NULL is not part of the public API, but internally it means don't set mObtained
649*b9df5ad1SAndroid Build Coastguard Worker return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
650*b9df5ad1SAndroid Build Coastguard Worker }
651*b9df5ad1SAndroid Build Coastguard Worker
flush(size_t * lost)652*b9df5ad1SAndroid Build Coastguard Worker ssize_t audio_utils_fifo_reader::flush(size_t *lost)
653*b9df5ad1SAndroid Build Coastguard Worker {
654*b9df5ad1SAndroid Build Coastguard Worker audio_utils_iovec iovec[2];
655*b9df5ad1SAndroid Build Coastguard Worker ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
656*b9df5ad1SAndroid Build Coastguard Worker if (ret > 0) {
657*b9df5ad1SAndroid Build Coastguard Worker size_t flushed = (size_t) ret;
658*b9df5ad1SAndroid Build Coastguard Worker release(flushed);
659*b9df5ad1SAndroid Build Coastguard Worker mTotalFlushed += flushed;
660*b9df5ad1SAndroid Build Coastguard Worker ret = flushed;
661*b9df5ad1SAndroid Build Coastguard Worker }
662*b9df5ad1SAndroid Build Coastguard Worker return ret;
663*b9df5ad1SAndroid Build Coastguard Worker }
664*b9df5ad1SAndroid Build Coastguard Worker
setHysteresis(int32_t armLevel,uint32_t triggerLevel)665*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
666*b9df5ad1SAndroid Build Coastguard Worker {
667*b9df5ad1SAndroid Build Coastguard Worker // cap to range [0, mFifo.mFrameCount]
668*b9df5ad1SAndroid Build Coastguard Worker if (armLevel < 0) {
669*b9df5ad1SAndroid Build Coastguard Worker armLevel = -1;
670*b9df5ad1SAndroid Build Coastguard Worker } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
671*b9df5ad1SAndroid Build Coastguard Worker armLevel = mFifo.mFrameCount;
672*b9df5ad1SAndroid Build Coastguard Worker }
673*b9df5ad1SAndroid Build Coastguard Worker if (triggerLevel > mFifo.mFrameCount) {
674*b9df5ad1SAndroid Build Coastguard Worker triggerLevel = mFifo.mFrameCount;
675*b9df5ad1SAndroid Build Coastguard Worker }
676*b9df5ad1SAndroid Build Coastguard Worker // TODO this is overly conservative; it would be better to arm based on actual fill level
677*b9df5ad1SAndroid Build Coastguard Worker if (armLevel < mArmLevel) {
678*b9df5ad1SAndroid Build Coastguard Worker mIsArmed = true;
679*b9df5ad1SAndroid Build Coastguard Worker }
680*b9df5ad1SAndroid Build Coastguard Worker mArmLevel = armLevel;
681*b9df5ad1SAndroid Build Coastguard Worker mTriggerLevel = triggerLevel;
682*b9df5ad1SAndroid Build Coastguard Worker }
683*b9df5ad1SAndroid Build Coastguard Worker
getHysteresis(int32_t * armLevel,uint32_t * triggerLevel) const684*b9df5ad1SAndroid Build Coastguard Worker void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
685*b9df5ad1SAndroid Build Coastguard Worker {
686*b9df5ad1SAndroid Build Coastguard Worker *armLevel = mArmLevel;
687*b9df5ad1SAndroid Build Coastguard Worker *triggerLevel = mTriggerLevel;
688*b9df5ad1SAndroid Build Coastguard Worker }
689