• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BufferQueueSource(const void * user,void * context,const void * caller)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 
~BufferQueueSource()53 BufferQueueSource::~BufferQueueSource() {
54     SL_LOGD("BufferQueueSource::~BufferQueueSource");
55 }
56 
57 
58 //--------------------------------------------------------------------------
initCheck() const59 status_t BufferQueueSource::initCheck() const {
60     return mAndroidBufferQueueSource != NULL ? OK : NO_INIT;
61 }
62 
readAt(off64_t offset,void * data,size_t size)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 
getSize(off64_t * size)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