• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 /* AndroidBufferQueue implementation */
18 
19 //#define USE_LOG SLAndroidLogLevel_Verbose
20 
21 #include "sles_allinclusive.h"
22 // for AAC ADTS verification on enqueue:
23 #include "android/include/AacBqToPcmCbRenderer.h"
24 
25 /**
26  * Determine the state of the audio player or audio recorder associated with a buffer queue.
27  *  Note that PLAYSTATE and RECORDSTATE values are equivalent (where PLAYING == RECORDING).
28  */
29 
getAssociatedState(IAndroidBufferQueue * thiz)30 static SLuint32 getAssociatedState(IAndroidBufferQueue *thiz)
31 {
32     SLuint32 state;
33     switch (InterfaceToObjectID(thiz)) {
34       case XA_OBJECTID_MEDIAPLAYER:
35         state = ((CMediaPlayer *) thiz->mThis)->mPlay.mState;
36         break;
37       case SL_OBJECTID_AUDIOPLAYER:
38         state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState;
39         break;
40       default:
41         // unreachable, but just in case we will assume it is stopped
42         assert(SL_BOOLEAN_FALSE);
43         state = SL_PLAYSTATE_STOPPED;
44         break;
45     }
46     return state;
47 }
48 
49 
50 /**
51  * parse and set the items associated with the given buffer, based on the buffer type,
52  * which determines the set of authorized items and format
53  */
setItems(const SLAndroidBufferItem * pItems,SLuint32 itemsLength,SLuint16 bufferType,AdvancedBufferHeader * pBuff)54 static void setItems(const SLAndroidBufferItem *pItems, SLuint32 itemsLength,
55         SLuint16 bufferType, AdvancedBufferHeader *pBuff)
56 {
57     // reset item structure based on type
58     switch (bufferType) {
59       case kAndroidBufferTypeMpeg2Ts:
60         pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
61         pBuff->mItems.mTsCmdData.mPts = 0;
62         break;
63       case kAndroidBufferTypeAacadts:
64         pBuff->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
65         break;
66       case kAndroidBufferTypeInvalid:
67       default:
68         // shouldn't happen, but just in case clear out the item structure
69         memset(&pBuff->mItems, 0, sizeof(AdvancedBufferItems));
70         return;
71     }
72 
73     // process all items in the array; if no items then we break out of loop immediately
74     while (itemsLength > 0) {
75 
76         // remaining length must be large enough for one full item without any associated data
77         if (itemsLength < sizeof(SLAndroidBufferItem)) {
78             SL_LOGE("Partial item at end of array ignored");
79             break;
80         }
81         itemsLength -= sizeof(SLAndroidBufferItem);
82 
83         // remaining length must be large enough for data with current item and alignment padding
84         SLuint32 itemDataSizeWithAlignmentPadding = (pItems->itemSize + 3) & ~3;
85         if (itemsLength < itemDataSizeWithAlignmentPadding) {
86             SL_LOGE("Partial item data at end of array ignored");
87             break;
88         }
89         itemsLength -= itemDataSizeWithAlignmentPadding;
90 
91         // parse item data based on type
92         switch (bufferType) {
93 
94           case kAndroidBufferTypeMpeg2Ts: {
95             switch (pItems->itemKey) {
96 
97               case SL_ANDROID_ITEMKEY_EOS:
98                 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS;
99                 //SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
100                 if (pItems->itemSize != 0) {
101                     SL_LOGE("Invalid item parameter size %u for EOS, ignoring value",
102                             pItems->itemSize);
103                 }
104                 break;
105 
106               case SL_ANDROID_ITEMKEY_DISCONTINUITY:
107                 if (pItems->itemSize == 0) {
108                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
109                     //SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
110                 } else if (pItems->itemSize == sizeof(SLAuint64)) {
111                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
112                     pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData);
113                     //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts);
114                 } else {
115                     SL_LOGE("Invalid item parameter size %u for MPEG-2 PTS, ignoring value",
116                             pItems->itemSize);
117                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
118                 }
119                 break;
120 
121               case SL_ANDROID_ITEMKEY_FORMAT_CHANGE:
122                 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE;
123                 if (pItems->itemSize != 0) {
124                     SL_LOGE("Invalid item parameter size %u for format change, ignoring value",
125                             pItems->itemSize);
126                 }
127                 break;
128 
129               default:
130                 // unknown item key
131                 SL_LOGE("Unknown item key %u with size %u ignored", pItems->itemKey,
132                         pItems->itemSize);
133                 break;
134 
135             }// switch (pItems->itemKey)
136           } break;
137 
138           case kAndroidBufferTypeAacadts: {
139             switch (pItems->itemKey) {
140 
141               case SL_ANDROID_ITEMKEY_EOS:
142                 pBuff->mItems.mAdtsCmdData.mAdtsCmdCode |= ANDROID_ADTSEVENT_EOS;
143                 if (pItems->itemSize != 0) {
144                     SL_LOGE("Invalid item parameter size %u for EOS, ignoring value",
145                             pItems->itemSize);
146                 }
147                 break;
148 
149               default:
150                 // unknown item key
151                 SL_LOGE("Unknown item key %u with size %u ignored", pItems->itemKey,
152                         pItems->itemSize);
153                 break;
154 
155             }// switch (pItems->itemKey)
156           } break;
157 
158           case kAndroidBufferTypeInvalid:
159           default:
160             // not reachable as we checked this earlier
161             return;
162 
163         }// switch (bufferType)
164 
165         // skip past this item, including data with alignment padding
166         pItems = (SLAndroidBufferItem *) ((char *) pItems +
167                 sizeof(SLAndroidBufferItem) + itemDataSizeWithAlignmentPadding);
168     }
169 
170     // now check for invalid combinations of items
171     switch (bufferType) {
172 
173       case kAndroidBufferTypeMpeg2Ts: {
174         // supported Mpeg2Ts commands are mutually exclusive
175         switch (pBuff->mItems.mTsCmdData.mTsCmdCode) {
176           // single items are allowed
177           case ANDROID_MP2TSEVENT_NONE:
178           case ANDROID_MP2TSEVENT_EOS:
179           case ANDROID_MP2TSEVENT_DISCONTINUITY:
180           case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
181           case ANDROID_MP2TSEVENT_FORMAT_CHANGE:
182             break;
183           // no combinations are allowed
184           default:
185             SL_LOGE("Invalid combination of items; all ignored");
186             pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
187             break;
188         }
189       } break;
190 
191       case kAndroidBufferTypeAacadts: {
192         // only one item supported, and thus no combination check needed
193       } break;
194 
195       case kAndroidBufferTypeInvalid:
196       default:
197         // not reachable as we checked this earlier
198         return;
199     }
200 
201 }
202 
203 
IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,slAndroidBufferQueueCallback callback,void * pContext)204 static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,
205         slAndroidBufferQueueCallback callback, void *pContext)
206 {
207     SL_ENTER_INTERFACE
208 
209     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
210 
211     interface_lock_exclusive(thiz);
212 
213     // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
214     if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
215         thiz->mCallback = callback;
216         thiz->mContext = pContext;
217 
218         // FIXME investigate why these two cases are not handled symmetrically any more
219         switch (InterfaceToObjectID(thiz)) {
220           case SL_OBJECTID_AUDIOPLAYER:
221             result = android_audioPlayer_androidBufferQueue_registerCallback_l(
222                     (CAudioPlayer*) thiz->mThis);
223             break;
224           case XA_OBJECTID_MEDIAPLAYER:
225             result = SL_RESULT_SUCCESS;
226             break;
227           default:
228             result = SL_RESULT_PARAMETER_INVALID;
229         }
230 
231     } else {
232         result = SL_RESULT_PRECONDITIONS_VIOLATED;
233     }
234 
235     interface_unlock_exclusive(thiz);
236 
237     SL_LEAVE_INTERFACE
238 }
239 
240 
IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)241 static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)
242 {
243     SL_ENTER_INTERFACE
244     result = SL_RESULT_SUCCESS;
245 
246     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
247 
248     interface_lock_exclusive(thiz);
249 
250     // reset the queue pointers
251     thiz->mFront = &thiz->mBufferArray[0];
252     thiz->mRear = &thiz->mBufferArray[0];
253     // reset the queue state
254     thiz->mState.count = 0;
255     thiz->mState.index = 0;
256     // reset the individual buffers
257     for (XAuint16 i=0 ; i<(thiz->mNumBuffers + 1) ; i++) {
258         thiz->mBufferArray[i].mDataBuffer = NULL;
259         thiz->mBufferArray[i].mDataSize = 0;
260         thiz->mBufferArray[i].mDataSizeConsumed = 0;
261         thiz->mBufferArray[i].mBufferContext = NULL;
262         thiz->mBufferArray[i].mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
263         switch (thiz->mBufferType) {
264           case kAndroidBufferTypeMpeg2Ts:
265             thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
266             thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0;
267             break;
268           case kAndroidBufferTypeAacadts:
269             thiz->mBufferArray[i].mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
270             break;
271           default:
272             result = SL_RESULT_CONTENT_UNSUPPORTED;
273         }
274     }
275 
276     if (SL_RESULT_SUCCESS == result) {
277         // object-specific behavior for a clear
278         switch (InterfaceToObjectID(thiz)) {
279         case SL_OBJECTID_AUDIOPLAYER:
280             result = SL_RESULT_SUCCESS;
281             android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
282             break;
283         case XA_OBJECTID_MEDIAPLAYER:
284             result = SL_RESULT_SUCCESS;
285             android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
286             break;
287         default:
288             result = SL_RESULT_PARAMETER_INVALID;
289         }
290     }
291 
292     interface_unlock_exclusive(thiz);
293 
294     SL_LEAVE_INTERFACE
295 }
296 
297 
IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,void * pBufferContext,void * pData,SLuint32 dataLength,const SLAndroidBufferItem * pItems,SLuint32 itemsLength)298 static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
299         void *pBufferContext,
300         void *pData,
301         SLuint32 dataLength,
302         const SLAndroidBufferItem *pItems,
303         SLuint32 itemsLength)
304 {
305     SL_ENTER_INTERFACE
306     SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength);
307 
308     if ((dataLength > 0) && (NULL == pData)) {
309         SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength);
310         result = SL_RESULT_PARAMETER_INVALID;
311     } else if ((itemsLength > 0) && (NULL == pItems)) {
312         SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength);
313         result = SL_RESULT_PARAMETER_INVALID;
314     } else if ((0 == dataLength) && (0 == itemsLength)) {
315         // no data and no msg
316         SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
317         result = SL_RESULT_PARAMETER_INVALID;
318     // Note that a non-NULL data pointer with zero data length is allowed.
319     // We track that data pointer as it moves through the queue
320     // to assist the application in accounting for data buffers.
321     // A non-NULL items pointer with zero items length is also allowed, but has no value.
322     } else {
323         IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
324 
325         // buffer size check, can be done outside of lock because buffer type can't change
326         switch (thiz->mBufferType) {
327           case kAndroidBufferTypeMpeg2Ts:
328             if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) {
329                 break;
330             }
331             SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)",
332                     MPEG2_TS_BLOCK_SIZE);
333             result = SL_RESULT_PARAMETER_INVALID;
334             SL_LEAVE_INTERFACE
335             break;
336           case kAndroidBufferTypeAacadts:
337             // non-zero dataLength is permitted in case of EOS command only
338             if (dataLength > 0) {
339                 result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(
340                     pData, dataLength);
341                 if (SL_RESULT_SUCCESS != result) {
342                     SL_LOGE("Error enqueueing ADTS data: data must start and end on frame "
343                             "boundaries");
344                     SL_LEAVE_INTERFACE
345                 }
346             }
347             break;
348           case kAndroidBufferTypeInvalid:
349           default:
350             result = SL_RESULT_PARAMETER_INVALID;
351             SL_LEAVE_INTERFACE
352         }
353 
354         interface_lock_exclusive(thiz);
355 
356         AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
357         if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
358             newRear = thiz->mBufferArray;
359         }
360         if (newRear == thiz->mFront) {
361             result = SL_RESULT_BUFFER_INSUFFICIENT;
362         } else {
363             oldRear->mDataBuffer = pData;
364             oldRear->mDataSize = dataLength;
365             oldRear->mDataSizeConsumed = 0;
366             oldRear->mBufferContext = pBufferContext;
367             oldRear->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
368             thiz->mRear = newRear;
369             ++thiz->mState.count;
370             // set oldRear->mItems based on items
371             setItems(pItems, itemsLength, thiz->mBufferType, oldRear);
372             result = SL_RESULT_SUCCESS;
373         }
374         // set enqueue attribute if state is PLAYING and the first buffer is enqueued
375         interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
376                 (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
377                         ATTR_ABQ_ENQUEUE : ATTR_NONE);
378     }
379 
380     SL_LEAVE_INTERFACE
381 }
382 
383 
IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,SLAndroidBufferQueueState * pState)384 static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
385         SLAndroidBufferQueueState *pState)
386 {
387     SL_ENTER_INTERFACE
388 
389     // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
390 
391     if (NULL == pState) {
392         result = SL_RESULT_PARAMETER_INVALID;
393     } else {
394         IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
395 
396         interface_lock_shared(thiz);
397 
398         pState->count = thiz->mState.count;
399         pState->index = thiz->mState.index;
400 
401         interface_unlock_shared(thiz);
402 
403         result = SL_RESULT_SUCCESS;
404     }
405 
406     SL_LEAVE_INTERFACE
407 }
408 
409 
IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,SLuint32 eventFlags)410 static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,
411         SLuint32 eventFlags)
412 {
413     SL_ENTER_INTERFACE
414 
415     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
416     interface_lock_exclusive(thiz);
417     // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation
418     if ((SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED == eventFlags) ||
419             (SL_ANDROIDBUFFERQUEUEEVENT_NONE == eventFlags)) {
420         thiz->mCallbackEventsMask = eventFlags;
421         result = SL_RESULT_SUCCESS;
422     } else {
423         result = SL_RESULT_FEATURE_UNSUPPORTED;
424     }
425     interface_unlock_exclusive(thiz);
426 
427     SL_LEAVE_INTERFACE
428 }
429 
430 
IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,SLuint32 * pEventFlags)431 static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,
432         SLuint32 *pEventFlags)
433 {
434     SL_ENTER_INTERFACE
435 
436     if (NULL == pEventFlags) {
437         result = SL_RESULT_PARAMETER_INVALID;
438     } else {
439         IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
440         interface_lock_shared(thiz);
441         SLuint32 callbackEventsMask = thiz->mCallbackEventsMask;
442         interface_unlock_shared(thiz);
443         *pEventFlags = callbackEventsMask;
444         result = SL_RESULT_SUCCESS;
445     }
446 
447     SL_LEAVE_INTERFACE
448 }
449 
450 
451 static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = {
452     IAndroidBufferQueue_RegisterCallback,
453     IAndroidBufferQueue_Clear,
454     IAndroidBufferQueue_Enqueue,
455     IAndroidBufferQueue_GetState,
456     IAndroidBufferQueue_SetCallbackEventsMask,
457     IAndroidBufferQueue_GetCallbackEventsMask
458 };
459 
460 
IAndroidBufferQueue_init(void * self)461 void IAndroidBufferQueue_init(void *self)
462 {
463     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
464     thiz->mItf = &IAndroidBufferQueue_Itf;
465 
466     thiz->mState.count = 0;
467     thiz->mState.index = 0;
468 
469     thiz->mCallback = NULL;
470     thiz->mContext = NULL;
471     thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED;
472 
473     thiz->mBufferType = kAndroidBufferTypeInvalid;
474     thiz->mBufferArray = NULL;
475     thiz->mFront = NULL;
476     thiz->mRear = NULL;
477 }
478 
479 
IAndroidBufferQueue_deinit(void * self)480 void IAndroidBufferQueue_deinit(void *self)
481 {
482     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
483     if (NULL != thiz->mBufferArray) {
484         free(thiz->mBufferArray);
485         thiz->mBufferArray = NULL;
486     }
487 }
488