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
BufferQueueSource(IAndroidBufferQueue * androidBufferQueue)39 BufferQueueSource::BufferQueueSource(IAndroidBufferQueue *androidBufferQueue) :
40 mAndroidBufferQueueSource(androidBufferQueue),
41 mStreamToBqOffset(0),
42 mEosReached(false)
43 {
44 }
45
46
~BufferQueueSource()47 BufferQueueSource::~BufferQueueSource() {
48 SL_LOGD("BufferQueueSource::~BufferQueueSource");
49 }
50
51
52 //--------------------------------------------------------------------------
initCheck() const53 status_t BufferQueueSource::initCheck() const {
54 return mAndroidBufferQueueSource != NULL ? OK : NO_INIT;
55 }
56
readAt(off64_t offset,void * data,size_t size)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
getSize(off64_t * size)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