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