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 #define LOG_TAG "AudioBufferProviderSource"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include <cutils/compiler.h>
     21 #include <utils/Log.h>
     22 #include <media/nbaio/AudioBufferProviderSource.h>
     23 
     24 namespace android {
     25 
     26 AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider,
     27                                                      NBAIO_Format format) :
     28     NBAIO_Source(format), mProvider(provider), mConsumed(0)
     29 {
     30     ALOG_ASSERT(provider != NULL);
     31     ALOG_ASSERT(format != Format_Invalid);
     32 }
     33 
     34 AudioBufferProviderSource::~AudioBufferProviderSource()
     35 {
     36     if (mBuffer.raw != NULL) {
     37         mProvider->releaseBuffer(&mBuffer);
     38     }
     39 }
     40 
     41 ssize_t AudioBufferProviderSource::availableToRead()
     42 {
     43     if (CC_UNLIKELY(!mNegotiated)) {
     44         return NEGOTIATE;
     45     }
     46     return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0;
     47 }
     48 
     49 ssize_t AudioBufferProviderSource::read(void *buffer,
     50                                         size_t count,
     51                                         int64_t readPTS)
     52 {
     53     if (CC_UNLIKELY(!mNegotiated)) {
     54         return NEGOTIATE;
     55     }
     56     if (CC_UNLIKELY(mBuffer.raw == NULL)) {
     57         mBuffer.frameCount = count;
     58         status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
     59         if (status != OK) {
     60             return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status;
     61         }
     62         ALOG_ASSERT(mBuffer.raw != NULL);
     63         // mConsumed is 0 either from constructor or after releaseBuffer()
     64     }
     65     size_t available = mBuffer.frameCount - mConsumed;
     66     if (CC_UNLIKELY(count > available)) {
     67         count = available;
     68     }
     69     // count could be zero, either because count was zero on entry or
     70     // available is zero, but both are unlikely so don't check for that
     71     memcpy(buffer, (char *) mBuffer.raw + (mConsumed << mBitShift), count << mBitShift);
     72     if (CC_UNLIKELY((mConsumed += count) >= mBuffer.frameCount)) {
     73         mProvider->releaseBuffer(&mBuffer);
     74         mBuffer.raw = NULL;
     75         mConsumed = 0;
     76     }
     77     mFramesRead += count;
     78     // For better responsiveness with large values of count,
     79     // return a short count rather than continuing with next buffer.
     80     // This gives the caller a chance to interpolate other actions.
     81     return count;
     82 }
     83 
     84 ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user,
     85                                            int64_t readPTS, size_t block)
     86 {
     87     if (CC_UNLIKELY(!mNegotiated)) {
     88         return NEGOTIATE;
     89     }
     90     if (CC_UNLIKELY(block == 0)) {
     91         block = ~0;
     92     }
     93     for (size_t accumulator = 0; ; ) {
     94         ALOG_ASSERT(accumulator <= total);
     95         size_t count = total - accumulator;
     96         if (CC_UNLIKELY(count == 0)) {
     97             return accumulator;
     98         }
     99         if (CC_LIKELY(count > block)) {
    100             count = block;
    101         }
    102         // 1 <= count <= block
    103         if (CC_UNLIKELY(mBuffer.raw == NULL)) {
    104             mBuffer.frameCount = count;
    105             status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
    106             if (CC_LIKELY(status == OK)) {
    107                 ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count);
    108                 // mConsumed is 0 either from constructor or after releaseBuffer()
    109                 continue;
    110             }
    111             // FIXME simplify logic - does the initial count and block checks again for no reason;
    112             //       don't you just want to fall through to the size_t available line?
    113             if (CC_LIKELY(status == NOT_ENOUGH_DATA)) {
    114                 status = WOULD_BLOCK;
    115             }
    116             return accumulator > 0 ? accumulator : (ssize_t) status;
    117         }
    118         size_t available = mBuffer.frameCount - mConsumed;
    119         if (CC_UNLIKELY(count > available)) {
    120             count = available;
    121         }
    122         if (CC_LIKELY(count > 0)) {
    123             char* readTgt = (char *) mBuffer.raw + (mConsumed << mBitShift);
    124             ssize_t ret = via(user, readTgt, count, readPTS);
    125             if (CC_UNLIKELY(ret <= 0)) {
    126                 if (CC_LIKELY(accumulator > 0)) {
    127                     return accumulator;
    128                 }
    129                 return ret;
    130             }
    131             ALOG_ASSERT((size_t) ret <= count);
    132             mFramesRead += ret;
    133             accumulator += ret;
    134             if (CC_LIKELY((mConsumed += ret) < mBuffer.frameCount)) {
    135                 continue;
    136             }
    137         }
    138         mProvider->releaseBuffer(&mBuffer);
    139         mBuffer.raw = NULL;
    140         mConsumed = 0;
    141         // don't get next buffer until we really need it
    142     }
    143 }
    144 
    145 }   // namespace android
    146