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 + 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