xref: /aosp_15_r20/system/media/audio_utils/fifo.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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