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 <common_time/cc_helper.h>
     23 #include <cutils/atomic.h>
     24 #include <cutils/compiler.h>
     25 #include <utils/LinearTransform.h>
     26 #include <utils/Log.h>
     27 #include <utils/Trace.h>
     28 #include <media/AudioBufferProvider.h>
     29 #include <media/nbaio/MonoPipe.h>
     30 #include <media/nbaio/roundup.h>
     31 
     32 
     33 namespace android {
     34 
     35 static uint64_t cacheN; // output of CCHelper::getLocalFreq()
     36 static bool cacheValid; // whether cacheN is valid
     37 static pthread_once_t cacheOnceControl = PTHREAD_ONCE_INIT;
     38 
     39 static void cacheOnceInit()
     40 {
     41     CCHelper tmpHelper;
     42     status_t res;
     43     if (OK != (res = tmpHelper.getLocalFreq(&cacheN))) {
     44         ALOGE("Failed to fetch local time frequency when constructing a"
     45               " MonoPipe (res = %d).  getNextWriteTimestamp calls will be"
     46               " non-functional", res);
     47         return;
     48     }
     49     cacheValid = true;
     50 }
     51 
     52 MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
     53         NBAIO_Sink(format),
     54         mUpdateSeq(0),
     55         mReqFrames(reqFrames),
     56         mMaxFrames(roundup(reqFrames)),
     57         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
     58         mFront(0),
     59         mRear(0),
     60         mWriteTsValid(false),
     61         // mWriteTs
     62         mSetpoint((reqFrames * 11) / 16),
     63         mWriteCanBlock(writeCanBlock),
     64         mIsShutdown(false),
     65         // mTimestampShared
     66         mTimestampMutator(&mTimestampShared),
     67         mTimestampObserver(&mTimestampShared)
     68 {
     69     uint64_t N, D;
     70 
     71     mNextRdPTS = AudioBufferProvider::kInvalidPTS;
     72 
     73     mSamplesToLocalTime.a_zero = 0;
     74     mSamplesToLocalTime.b_zero = 0;
     75     mSamplesToLocalTime.a_to_b_numer = 0;
     76     mSamplesToLocalTime.a_to_b_denom = 0;
     77 
     78     D = Format_sampleRate(format);
     79 
     80     (void) pthread_once(&cacheOnceControl, cacheOnceInit);
     81     if (!cacheValid) {
     82         // log has already been done
     83         return;
     84     }
     85     N = cacheN;
     86 
     87     LinearTransform::reduce(&N, &D);
     88     static const uint64_t kSignedHiBitsMask   = ~(0x7FFFFFFFull);
     89     static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull);
     90     if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) {
     91         ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit"
     92               " in a 32/32 bit rational.  (max reduction is 0x%016" PRIx64 "/0x%016" PRIx64
     93               ").  getNextWriteTimestamp calls will be non-functional", N, D);
     94         return;
     95     }
     96 
     97     mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N);
     98     mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D);
     99 }
    100 
    101 MonoPipe::~MonoPipe()
    102 {
    103     free(mBuffer);
    104 }
    105 
    106 ssize_t MonoPipe::availableToWrite() const
    107 {
    108     if (CC_UNLIKELY(!mNegotiated)) {
    109         return NEGOTIATE;
    110     }
    111     // uses mMaxFrames not mReqFrames, so allows "over-filling" the pipe beyond requested limit
    112     ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
    113     ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
    114     return ret;
    115 }
    116 
    117 ssize_t MonoPipe::write(const void *buffer, size_t count)
    118 {
    119     if (CC_UNLIKELY(!mNegotiated)) {
    120         return NEGOTIATE;
    121     }
    122     size_t totalFramesWritten = 0;
    123     while (count > 0) {
    124         // can't return a negative value, as we already checked for !mNegotiated
    125         size_t avail = availableToWrite();
    126         size_t written = avail;
    127         if (CC_LIKELY(written > count)) {
    128             written = count;
    129         }
    130         size_t rear = mRear & (mMaxFrames - 1);
    131         size_t part1 = mMaxFrames - rear;
    132         if (part1 > written) {
    133             part1 = written;
    134         }
    135         if (CC_LIKELY(part1 > 0)) {
    136             memcpy((char *) mBuffer + (rear * mFrameSize), buffer, part1 * mFrameSize);
    137             if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
    138                 size_t part2 = written - part1;
    139                 if (CC_LIKELY(part2 > 0)) {
    140                     memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize);
    141                 }
    142             }
    143             android_atomic_release_store(written + mRear, &mRear);
    144             totalFramesWritten += written;
    145         }
    146         if (!mWriteCanBlock || mIsShutdown) {
    147             break;
    148         }
    149         count -= written;
    150         buffer = (char *) buffer + (written * mFrameSize);
    151         // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
    152         // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
    153         uint32_t ns;
    154         if (written > 0) {
    155             size_t filled = (mMaxFrames - avail) + written;
    156             // FIXME cache these values to avoid re-computation
    157             if (filled <= mSetpoint / 2) {
    158                 // pipe is (nearly) empty, fill quickly
    159                 ns = written * ( 500000000 / Format_sampleRate(mFormat));
    160             } else if (filled <= (mSetpoint * 3) / 4) {
    161                 // pipe is below setpoint, fill at slightly faster rate
    162                 ns = written * ( 750000000 / Format_sampleRate(mFormat));
    163             } else if (filled <= (mSetpoint * 5) / 4) {
    164                 // pipe is at setpoint, fill at nominal rate
    165                 ns = written * (1000000000 / Format_sampleRate(mFormat));
    166             } else if (filled <= (mSetpoint * 3) / 2) {
    167                 // pipe is above setpoint, fill at slightly slower rate
    168                 ns = written * (1150000000 / Format_sampleRate(mFormat));
    169             } else if (filled <= (mSetpoint * 7) / 4) {
    170                 // pipe is overflowing, fill slowly
    171                 ns = written * (1350000000 / Format_sampleRate(mFormat));
    172             } else {
    173                 // pipe is severely overflowing
    174                 ns = written * (1750000000 / Format_sampleRate(mFormat));
    175             }
    176         } else {
    177             ns = count * (1350000000 / Format_sampleRate(mFormat));
    178         }
    179         if (ns > 999999999) {
    180             ns = 999999999;
    181         }
    182         struct timespec nowTs;
    183         bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs);
    184         // deduct the elapsed time since previous write() completed
    185         if (nowTsValid && mWriteTsValid) {
    186             time_t sec = nowTs.tv_sec - mWriteTs.tv_sec;
    187             long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec;
    188             ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
    189                     "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
    190                     mWriteTs.tv_sec, mWriteTs.tv_nsec, nowTs.tv_sec, nowTs.tv_nsec);
    191             if (nsec < 0) {
    192                 --sec;
    193                 nsec += 1000000000;
    194             }
    195             if (sec == 0) {
    196                 if ((long) ns > nsec) {
    197                     ns -= nsec;
    198                 } else {
    199                     ns = 0;
    200                 }
    201             }
    202         }
    203         if (ns > 0) {
    204             const struct timespec req = {0, static_cast<long>(ns)};
    205             nanosleep(&req, NULL);
    206         }
    207         // record the time that this write() completed
    208         if (nowTsValid) {
    209             mWriteTs = nowTs;
    210             if ((mWriteTs.tv_nsec += ns) >= 1000000000) {
    211                 mWriteTs.tv_nsec -= 1000000000;
    212                 ++mWriteTs.tv_sec;
    213             }
    214         }
    215         mWriteTsValid = nowTsValid;
    216     }
    217     mFramesWritten += totalFramesWritten;
    218     return totalFramesWritten;
    219 }
    220 
    221 void MonoPipe::setAvgFrames(size_t setpoint)
    222 {
    223     mSetpoint = setpoint;
    224 }
    225 
    226 status_t MonoPipe::getNextWriteTimestamp(int64_t *timestamp)
    227 {
    228     int32_t front;
    229 
    230     ALOG_ASSERT(NULL != timestamp);
    231 
    232     if (0 == mSamplesToLocalTime.a_to_b_denom)
    233         return UNKNOWN_ERROR;
    234 
    235     observeFrontAndNRPTS(&front, timestamp);
    236 
    237     if (AudioBufferProvider::kInvalidPTS != *timestamp) {
    238         // If we have a valid read-pointer and next read timestamp pair, then
    239         // use the current value of the write pointer to figure out how many
    240         // frames are in the buffer, and offset the timestamp by that amt.  Then
    241         // next time we write to the MonoPipe, the data will hit the speakers at
    242         // the next read timestamp plus the current amount of data in the
    243         // MonoPipe.
    244         size_t pendingFrames = (mRear - front) & (mMaxFrames - 1);
    245         *timestamp = offsetTimestampByAudioFrames(*timestamp, pendingFrames);
    246     }
    247 
    248     return OK;
    249 }
    250 
    251 void MonoPipe::updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS)
    252 {
    253     // Set the MSB of the update sequence number to indicate that there is a
    254     // multi-variable update in progress.  Use an atomic store with an "acquire"
    255     // barrier to make sure that the next operations cannot be re-ordered and
    256     // take place before the change to mUpdateSeq is commited..
    257     int32_t tmp = mUpdateSeq | 0x80000000;
    258     android_atomic_acquire_store(tmp, &mUpdateSeq);
    259 
    260     // Update mFront and mNextRdPTS
    261     mFront = newFront;
    262     mNextRdPTS = newNextRdPTS;
    263 
    264     // We are finished with the update.  Compute the next sequnce number (which
    265     // should be the old sequence number, plus one, and with the MSB cleared)
    266     // and then store it in mUpdateSeq using an atomic store with a "release"
    267     // barrier so our update operations cannot be re-ordered past the update of
    268     // the sequence number.
    269     tmp = (tmp + 1) & 0x7FFFFFFF;
    270     android_atomic_release_store(tmp, &mUpdateSeq);
    271 }
    272 
    273 void MonoPipe::observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS)
    274 {
    275     // Perform an atomic observation of mFront and mNextRdPTS.  Basically,
    276     // atomically observe the sequence number, then observer the variables, then
    277     // atomically observe the sequence number again.  If the two observations of
    278     // the sequence number match, and the update-in-progress bit was not set,
    279     // then we know we have a successful atomic observation.  Otherwise, we loop
    280     // around and try again.
    281     //
    282     // Note, it is very important that the observer be a lower priority thread
    283     // than the updater.  If the updater is lower than the observer, or they are
    284     // the same priority and running with SCHED_FIFO (implying that quantum
    285     // based premption is disabled) then we run the risk of deadlock.
    286     int32_t seqOne, seqTwo;
    287 
    288     do {
    289         seqOne        = android_atomic_acquire_load(&mUpdateSeq);
    290         *outFront     = mFront;
    291         *outNextRdPTS = mNextRdPTS;
    292         seqTwo        = android_atomic_release_load(&mUpdateSeq);
    293     } while ((seqOne != seqTwo) || (seqOne & 0x80000000));
    294 }
    295 
    296 int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames)
    297 {
    298     if (0 == mSamplesToLocalTime.a_to_b_denom)
    299         return AudioBufferProvider::kInvalidPTS;
    300 
    301     if (ts == AudioBufferProvider::kInvalidPTS)
    302         return AudioBufferProvider::kInvalidPTS;
    303 
    304     int64_t frame_lt_duration;
    305     if (!mSamplesToLocalTime.doForwardTransform(audFrames,
    306                                                 &frame_lt_duration)) {
    307         // This should never fail, but if there is a bug which is causing it
    308         // to fail, this message would probably end up flooding the logs
    309         // because the conversion would probably fail forever.  Log the
    310         // error, but then zero out the ratio in the linear transform so
    311         // that we don't try to do any conversions from now on.  This
    312         // MonoPipe's getNextWriteTimestamp is now broken for good.
    313         ALOGE("Overflow when attempting to convert %zu audio frames to"
    314               " duration in local time.  getNextWriteTimestamp will fail from"
    315               " now on.", audFrames);
    316         mSamplesToLocalTime.a_to_b_numer = 0;
    317         mSamplesToLocalTime.a_to_b_denom = 0;
    318         return AudioBufferProvider::kInvalidPTS;
    319     }
    320 
    321     return ts + frame_lt_duration;
    322 }
    323 
    324 void MonoPipe::shutdown(bool newState)
    325 {
    326     mIsShutdown = newState;
    327 }
    328 
    329 bool MonoPipe::isShutdown()
    330 {
    331     return mIsShutdown;
    332 }
    333 
    334 status_t MonoPipe::getTimestamp(AudioTimestamp& timestamp)
    335 {
    336     if (mTimestampObserver.poll(timestamp)) {
    337         return OK;
    338     }
    339     return INVALID_OPERATION;
    340 }
    341 
    342 }   // namespace android
    343