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