Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2011 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 USE_LOG SLAndroidLogLevel_Verbose
     18 
     19 #include "sles_allinclusive.h"
     20 #include "android/BufferQueueSource.h"
     21 
     22 #include <media/stagefright/MediaDebug.h>
     23 #include <sys/types.h>
     24 #include <unistd.h>
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <fcntl.h>
     28 
     29 namespace android {
     30 
     31 
     32 const SLuint32 BufferQueueSource::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
     33         SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
     34         sizeof(SLuint32),                    // item size
     35         SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
     36 };
     37 
     38 
     39 BufferQueueSource::BufferQueueSource(const void* user, void *context,  const void *caller) :
     40           mAndroidBufferQueueSource(NULL),
     41           mStreamToBqOffset(0),
     42           mEosReached(false)
     43 {
     44     if (NULL != user) {
     45         mAndroidBufferQueueSource = &((CAudioPlayer*)user)->mAndroidBufferQueue;
     46     } else {
     47         SL_LOGE("Can't create BufferQueueSource with NULL user");
     48     }
     49 
     50 }
     51 
     52 
     53 BufferQueueSource::~BufferQueueSource() {
     54     SL_LOGD("BufferQueueSource::~BufferQueueSource");
     55 }
     56 
     57 
     58 //--------------------------------------------------------------------------
     59 status_t BufferQueueSource::initCheck() const {
     60     return mAndroidBufferQueueSource != NULL ? OK : NO_INIT;
     61 }
     62 
     63 ssize_t BufferQueueSource::readAt(off64_t offset, void *data, size_t size) {
     64     SL_LOGD("BufferQueueSource::readAt(offset=%lld, data=%p, size=%d)", offset, data, size);
     65 
     66     if (mEosReached) {
     67         // once EOS has been received from the buffer queue, you can't read anymore
     68         return 0;
     69     }
     70 
     71     ssize_t readSize;
     72     slAndroidBufferQueueCallback callback = NULL;
     73     void* pBufferContext, *pBufferData, *callbackPContext;
     74     uint32_t dataSize, dataUsed;
     75 
     76     interface_lock_exclusive(mAndroidBufferQueueSource);
     77 
     78     if (mAndroidBufferQueueSource->mState.count == 0) {
     79         readSize = 0;
     80     } else {
     81         assert(mAndroidBufferQueueSource->mFront != mAndroidBufferQueueSource->mRear);
     82 
     83         AdvancedBufferHeader *oldFront = mAndroidBufferQueueSource->mFront;
     84         AdvancedBufferHeader *newFront = &oldFront[1];
     85 
     86         // where to read from
     87         char *pSrc = NULL;
     88         // can this read operation cause us to call the buffer queue callback
     89         // (either because there was a command with no data, or all the data has been consumed)
     90         bool queueCallbackCandidate = false;
     91 
     92         // consume events when starting to read data from a buffer for the first time
     93         if (oldFront->mDataSizeConsumed == 0) {
     94             if (oldFront->mItems.mAdtsCmdData.mAdtsCmdCode & ANDROID_ADTSEVENT_EOS) {
     95                 mEosReached = true;
     96                 // EOS has no associated data
     97                 queueCallbackCandidate = true;
     98             }
     99             oldFront->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
    100         }
    101 
    102         //assert(mStreamToBqOffset <= offset);
    103         CHECK(mStreamToBqOffset <= offset);
    104 
    105         if (offset + size <= mStreamToBqOffset + oldFront->mDataSize) {
    106             pSrc = ((char*)oldFront->mDataBuffer) + (offset - mStreamToBqOffset);
    107 
    108             if (offset - mStreamToBqOffset + size == oldFront->mDataSize) {
    109                 // consumed buffer entirely
    110                 oldFront->mDataSizeConsumed = oldFront->mDataSize;
    111                 mStreamToBqOffset += oldFront->mDataSize;
    112                 queueCallbackCandidate = true;
    113 
    114                 // move queue to next buffer
    115                 if (newFront == &mAndroidBufferQueueSource->
    116                         mBufferArray[mAndroidBufferQueueSource->mNumBuffers + 1]) {
    117                     // reached the end, circle back
    118                     newFront = mAndroidBufferQueueSource->mBufferArray;
    119                 }
    120                 mAndroidBufferQueueSource->mFront = newFront;
    121                 // update the queue state
    122                 mAndroidBufferQueueSource->mState.count--;
    123                 mAndroidBufferQueueSource->mState.index++;
    124                 SL_LOGV("BufferQueueSource moving to next buffer");
    125             }
    126         }
    127 
    128         // consume data: copy to given destination
    129         if (NULL != pSrc) {
    130             memcpy(data, pSrc, size);
    131             readSize = size;
    132         } else {
    133             readSize = 0;
    134         }
    135 
    136         if (queueCallbackCandidate) {
    137             // data has been consumed, and the buffer queue state has been updated
    138             // we will notify the client if applicable
    139             if (mAndroidBufferQueueSource->mCallbackEventsMask &
    140                     SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
    141                 callback = mAndroidBufferQueueSource->mCallback;
    142                 // save callback data while under lock
    143                 callbackPContext = mAndroidBufferQueueSource->mContext;
    144                 pBufferContext = (void *)oldFront->mBufferContext;
    145                 pBufferData    = (void *)oldFront->mDataBuffer;
    146                 dataSize       = oldFront->mDataSize;
    147                 dataUsed       = oldFront->mDataSizeConsumed;
    148             }
    149         }
    150     }
    151 
    152     interface_unlock_exclusive(mAndroidBufferQueueSource);
    153 
    154     // notify client
    155     if (NULL != callback) {
    156         SLresult result = (*callback)(&mAndroidBufferQueueSource->mItf, callbackPContext,
    157                 pBufferContext, pBufferData, dataSize, dataUsed,
    158                 // no messages during playback other than marking the buffer as processed
    159                 (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
    160                 NB_BUFFEREVENT_ITEM_FIELDS * sizeof(SLuint32) /* itemsLength */ );
    161         if (SL_RESULT_SUCCESS != result) {
    162             // Reserved for future use
    163             SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
    164         }
    165     }
    166 
    167     return readSize;
    168 }
    169 
    170 
    171 status_t BufferQueueSource::getSize(off64_t *size) {
    172     SL_LOGD("BufferQueueSource::getSize()");
    173     // we're streaming, we don't know how much there is
    174     *size = 0;
    175     return OK;
    176 }
    177 
    178 }  // namespace android
    179