Home | History | Annotate | Download | only in libnbaio
      1 /*
      2  * Copyright (C) 2012 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 #include <inttypes.h>
     18 
     19 #define LOG_TAG "MonoPipe"
     20 //#define LOG_NDEBUG 0
     21 
     22 #include <cutils/compiler.h>
     23 #include <utils/Log.h>
     24 #include <utils/Trace.h>
     25 #include <media/AudioBufferProvider.h>
     26 #include <media/nbaio/MonoPipe.h>
     27 #include <audio_utils/roundup.h>
     28 
     29 
     30 namespace android {
     31 
     32 MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
     33         NBAIO_Sink(format),
     34         // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
     35         mMaxFrames(roundup(reqFrames)),
     36         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
     37         mFifo(mMaxFrames, Format_frameSize(format), mBuffer, true /*throttlesWriter*/),
     38         mFifoWriter(mFifo),
     39         mWriteTsValid(false),
     40         // mWriteTs
     41         mSetpoint((reqFrames * 11) / 16),
     42         mWriteCanBlock(writeCanBlock),
     43         mIsShutdown(false),
     44         // mTimestampShared
     45         mTimestampMutator(&mTimestampShared),
     46         mTimestampObserver(&mTimestampShared)
     47 {
     48 }
     49 
     50 MonoPipe::~MonoPipe()
     51 {
     52     free(mBuffer);
     53 }
     54 
     55 ssize_t MonoPipe::availableToWrite()
     56 {
     57     if (CC_UNLIKELY(!mNegotiated)) {
     58         return NEGOTIATE;
     59     }
     60     // uses mMaxFrames not reqFrames, so allows "over-filling" the pipe beyond requested limit
     61     ssize_t ret = mFifoWriter.available();
     62     ALOG_ASSERT(ret <= mMaxFrames);
     63     return ret;
     64 }
     65 
     66 ssize_t MonoPipe::write(const void *buffer, size_t count)
     67 {
     68     if (CC_UNLIKELY(!mNegotiated)) {
     69         return NEGOTIATE;
     70     }
     71     size_t totalFramesWritten = 0;
     72     while (count > 0) {
     73         ssize_t actual = mFifoWriter.write(buffer, count);
     74         ALOG_ASSERT(actual <= count);
     75         if (actual < 0) {
     76             if (totalFramesWritten == 0) {
     77                 return actual;
     78             }
     79             break;
     80         }
     81         size_t written = (size_t) actual;
     82         totalFramesWritten += written;
     83         if (!mWriteCanBlock || mIsShutdown) {
     84             break;
     85         }
     86         count -= written;
     87         buffer = (char *) buffer + (written * mFrameSize);
     88         // TODO Replace this whole section by audio_util_fifo's setpoint feature.
     89         // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
     90         // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
     91         uint32_t ns;
     92         if (written > 0) {
     93             ssize_t avail = mFifoWriter.available();
     94             ALOG_ASSERT(avail <= mMaxFrames);
     95             if (avail < 0) {
     96                 // don't return avail as status, because totalFramesWritten > 0
     97                 break;
     98             }
     99             size_t filled = mMaxFrames - (size_t) avail;
    100             // FIXME cache these values to avoid re-computation
    101             if (filled <= mSetpoint / 2) {
    102                 // pipe is (nearly) empty, fill quickly
    103                 ns = written * ( 500000000 / Format_sampleRate(mFormat));
    104             } else if (filled <= (mSetpoint * 3) / 4) {
    105                 // pipe is below setpoint, fill at slightly faster rate
    106                 ns = written * ( 750000000 / Format_sampleRate(mFormat));
    107             } else if (filled <= (mSetpoint * 5) / 4) {
    108                 // pipe is at setpoint, fill at nominal rate
    109                 ns = written * (1000000000 / Format_sampleRate(mFormat));
    110             } else if (filled <= (mSetpoint * 3) / 2) {
    111                 // pipe is above setpoint, fill at slightly slower rate
    112                 ns = written * (1150000000 / Format_sampleRate(mFormat));
    113             } else if (filled <= (mSetpoint * 7) / 4) {
    114                 // pipe is overflowing, fill slowly
    115                 ns = written * (1350000000 / Format_sampleRate(mFormat));
    116             } else {
    117                 // pipe is severely overflowing
    118                 ns = written * (1750000000 / Format_sampleRate(mFormat));
    119             }
    120         } else {
    121             ns = count * (1350000000 / Format_sampleRate(mFormat));
    122         }
    123         if (ns > 999999999) {
    124             ns = 999999999;
    125         }
    126         struct timespec nowTs;
    127         bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs);
    128         // deduct the elapsed time since previous write() completed
    129         if (nowTsValid && mWriteTsValid) {
    130             time_t sec = nowTs.tv_sec - mWriteTs.tv_sec;
    131             long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec;
    132             ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
    133                     "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
    134                     mWriteTs.tv_sec, mWriteTs.tv_nsec, nowTs.tv_sec, nowTs.tv_nsec);
    135             if (nsec < 0) {
    136                 --sec;
    137                 nsec += 1000000000;
    138             }
    139             if (sec == 0) {
    140                 if ((long) ns > nsec) {
    141                     ns -= nsec;
    142                 } else {
    143                     ns = 0;
    144                 }
    145             }
    146         }
    147         if (ns > 0) {
    148             const struct timespec req = {0, static_cast<long>(ns)};
    149             nanosleep(&req, NULL);
    150         }
    151         // record the time that this write() completed
    152         if (nowTsValid) {
    153             mWriteTs = nowTs;
    154             if ((mWriteTs.tv_nsec += ns) >= 1000000000) {
    155                 mWriteTs.tv_nsec -= 1000000000;
    156                 ++mWriteTs.tv_sec;
    157             }
    158         }
    159         mWriteTsValid = nowTsValid;
    160     }
    161     mFramesWritten += totalFramesWritten;
    162     return totalFramesWritten;
    163 }
    164 
    165 void MonoPipe::setAvgFrames(size_t setpoint)
    166 {
    167     mSetpoint = setpoint;
    168 }
    169 
    170 void MonoPipe::shutdown(bool newState)
    171 {
    172     mIsShutdown = newState;
    173 }
    174 
    175 bool MonoPipe::isShutdown()
    176 {
    177     return mIsShutdown;
    178 }
    179 
    180 status_t MonoPipe::getTimestamp(ExtendedTimestamp &timestamp)
    181 {
    182     ExtendedTimestamp ets;
    183     if (mTimestampObserver.poll(ets)) {
    184         timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
    185                 ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
    186         timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
    187                 ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
    188         return OK;
    189     }
    190     return INVALID_OPERATION;
    191 }
    192 
    193 }   // namespace android
    194