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 media player 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(SLuint32 dataLength,const SLAndroidBufferItem * pItems,SLuint32 itemsLength,SLuint16 bufferType,AdvancedBufferHeader * pBuff,bool * pEOS)54 static SLresult setItems(SLuint32 dataLength,
55         const SLAndroidBufferItem *pItems, SLuint32 itemsLength,
56         SLuint16 bufferType, AdvancedBufferHeader *pBuff, bool *pEOS)
57 {
58     // reset item structure based on type
59     switch (bufferType) {
60       case kAndroidBufferTypeMpeg2Ts:
61         pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
62         pBuff->mItems.mTsCmdData.mPts = 0;
63         break;
64       case kAndroidBufferTypeAacadts:
65         pBuff->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
66         break;
67       case kAndroidBufferTypeInvalid:
68       default:
69         // shouldn't happen, but just in case clear out the item structure
70         memset(&pBuff->mItems, 0, sizeof(AdvancedBufferItems));
71         return SL_RESULT_INTERNAL_ERROR;
72     }
73 
74     // process all items in the array; if no items then we break out of loop immediately
75     while (itemsLength > 0) {
76 
77         // remaining length must be large enough for one full item without any associated data
78         if (itemsLength < sizeof(SLAndroidBufferItem)) {
79             SL_LOGE("Partial item at end of array");
80             return SL_RESULT_PARAMETER_INVALID;
81         }
82         itemsLength -= sizeof(SLAndroidBufferItem);
83 
84         // remaining length must be large enough for data with current item and alignment padding
85         SLuint32 itemDataSizeWithAlignmentPadding = (pItems->itemSize + 3) & ~3;
86         if (itemsLength < itemDataSizeWithAlignmentPadding) {
87             SL_LOGE("Partial item data at end of array");
88             return SL_RESULT_PARAMETER_INVALID;
89         }
90         itemsLength -= itemDataSizeWithAlignmentPadding;
91 
92         // parse item data based on type
93         switch (bufferType) {
94 
95           case kAndroidBufferTypeMpeg2Ts: {
96             switch (pItems->itemKey) {
97 
98               case SL_ANDROID_ITEMKEY_EOS:
99                 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS;
100                 //SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
101                 if (pItems->itemSize != 0) {
102                     SL_LOGE("Invalid item parameter size %u for EOS", pItems->itemSize);
103                     return SL_RESULT_PARAMETER_INVALID;
104                 }
105                 break;
106 
107               case SL_ANDROID_ITEMKEY_DISCONTINUITY:
108                 if (pItems->itemSize == 0) {
109                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
110                     //SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
111                 } else if (pItems->itemSize == sizeof(SLAuint64)) {
112                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
113                     pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData);
114                     //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts);
115                 } else {
116                     SL_LOGE("Invalid item parameter size %u for MPEG-2 PTS", pItems->itemSize);
117                     return SL_RESULT_PARAMETER_INVALID;
118                 }
119                 break;
120 
121               case SL_ANDROID_ITEMKEY_FORMAT_CHANGE:
122                 // distinguish between a "full" format change and one where it says what changed
123                 if (pItems->itemSize == 0) {
124                     SL_LOGV("Received format change with no data == full format change");
125                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL;
126                 } else if (pItems->itemSize == sizeof(SLuint32)) {
127                     XAuint32 formatData = *((XAuint32*)pItems->itemData);
128                     // intentionally only supporting video change when reading which specific
129                     //    stream has changed, interpret other changes as full change
130                     if (formatData == XA_ANDROID_FORMATCHANGE_ITEMDATA_VIDEO) {
131                         pBuff->mItems.mTsCmdData.mTsCmdCode |=
132                                 ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO;
133                         SL_LOGV("Received video format change");
134                     } else {
135                         // note that we don't support specifying
136                         //    ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL by having all bits of
137                         //    the data mask set, we default to it with unsupported masks
138                         SL_LOGE("Received format change with unsupported data, ignoring data");
139                         pBuff->mItems.mTsCmdData.mTsCmdCode |=
140                                 ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL;
141                     }
142                 } else {
143                     SL_LOGE("Received format change with invalid data size, ignoring data");
144                     pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL;
145                 }
146                 break;
147 
148               default:
149                 // unknown item key
150                 SL_LOGE("Unknown item key %u with size %u", pItems->itemKey, pItems->itemSize);
151                 return SL_RESULT_PARAMETER_INVALID;
152 
153             }// switch (pItems->itemKey)
154           } break;
155 
156           case kAndroidBufferTypeAacadts: {
157             switch (pItems->itemKey) {
158 
159               case SL_ANDROID_ITEMKEY_EOS:
160                 pBuff->mItems.mAdtsCmdData.mAdtsCmdCode |= ANDROID_ADTSEVENT_EOS;
161                 if (pItems->itemSize != 0) {
162                     SL_LOGE("Invalid item parameter size %u for EOS", pItems->itemSize);
163                     return SL_RESULT_PARAMETER_INVALID;
164                 }
165                 break;
166 
167               default:
168                 // unknown item key
169                 SL_LOGE("Unknown item key %u with size %u", pItems->itemKey, pItems->itemSize);
170                 return SL_RESULT_PARAMETER_INVALID;
171 
172             }// switch (pItems->itemKey)
173           } break;
174 
175           case kAndroidBufferTypeInvalid:
176           default:
177             // not reachable as we checked this earlier
178             return SL_RESULT_INTERNAL_ERROR;
179 
180         }// switch (bufferType)
181 
182         // skip past this item, including data with alignment padding
183         pItems = (SLAndroidBufferItem *) ((char *) pItems +
184                 sizeof(SLAndroidBufferItem) + itemDataSizeWithAlignmentPadding);
185     }
186 
187     // now check for invalid combinations of items
188     switch (bufferType) {
189 
190       case kAndroidBufferTypeMpeg2Ts: {
191         // supported Mpeg2Ts commands are mutually exclusive
192         switch (pBuff->mItems.mTsCmdData.mTsCmdCode) {
193           // single items are allowed
194           case ANDROID_MP2TSEVENT_EOS:
195             if (dataLength > 0) {
196                 SL_LOGE("Can't enqueue non-zero data with EOS");
197                 return SL_RESULT_PRECONDITIONS_VIOLATED;
198             }
199             *pEOS = true;
200             break;
201           case ANDROID_MP2TSEVENT_NONE:
202           case ANDROID_MP2TSEVENT_DISCONTINUITY:
203           case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
204           case ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL:
205           case ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO:
206             break;
207           // no combinations are allowed
208           default:
209             SL_LOGE("Invalid combination of items");
210             return SL_RESULT_PARAMETER_INVALID;
211         }
212       } break;
213 
214       case kAndroidBufferTypeAacadts: {
215         // only one item supported, and thus no combination check needed
216         if (pBuff->mItems.mAdtsCmdData.mAdtsCmdCode == ANDROID_ADTSEVENT_EOS) {
217             if (dataLength > 0) {
218                 SL_LOGE("Can't enqueue non-zero data with EOS");
219                 return SL_RESULT_PRECONDITIONS_VIOLATED;
220             }
221             *pEOS = true;
222         }
223       } break;
224 
225       case kAndroidBufferTypeInvalid:
226       default:
227         // not reachable as we checked this earlier
228         return SL_RESULT_INTERNAL_ERROR;
229     }
230 
231     return SL_RESULT_SUCCESS;
232 }
233 
234 
IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,slAndroidBufferQueueCallback callback,void * pContext)235 static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,
236         slAndroidBufferQueueCallback callback, void *pContext)
237 {
238     SL_ENTER_INTERFACE
239 
240     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
241 
242     interface_lock_exclusive(thiz);
243 
244     // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
245     if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
246         thiz->mCallback = callback;
247         thiz->mContext = pContext;
248         result = SL_RESULT_SUCCESS;
249 
250     } else {
251         result = SL_RESULT_PRECONDITIONS_VIOLATED;
252     }
253 
254     interface_unlock_exclusive(thiz);
255 
256     SL_LEAVE_INTERFACE
257 }
258 
259 
IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)260 static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)
261 {
262     SL_ENTER_INTERFACE
263     result = SL_RESULT_SUCCESS;
264 
265     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
266 
267     interface_lock_exclusive(thiz);
268 
269     // reset the queue pointers
270     thiz->mFront = &thiz->mBufferArray[0];
271     thiz->mRear = &thiz->mBufferArray[0];
272     // reset the queue state
273     thiz->mState.count = 0;
274     thiz->mState.index = 0;
275 
276     // object-specific behavior for a clear
277     switch (InterfaceToObjectID(thiz)) {
278     case SL_OBJECTID_AUDIOPLAYER:
279         android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
280         break;
281     case XA_OBJECTID_MEDIAPLAYER:
282         android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
283         break;
284     default:
285         result = SL_RESULT_PARAMETER_INVALID;
286     }
287 
288     interface_unlock_exclusive(thiz);
289 
290     SL_LEAVE_INTERFACE
291 }
292 
293 
IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,void * pBufferContext,void * pData,SLuint32 dataLength,const SLAndroidBufferItem * pItems,SLuint32 itemsLength)294 static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
295         void *pBufferContext,
296         void *pData,
297         SLuint32 dataLength,
298         const SLAndroidBufferItem *pItems,
299         SLuint32 itemsLength)
300 {
301     SL_ENTER_INTERFACE
302     SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength);
303 
304     if ((dataLength > 0) && (NULL == pData)) {
305         SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength);
306         result = SL_RESULT_PARAMETER_INVALID;
307     } else if ((itemsLength > 0) && (NULL == pItems)) {
308         SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength);
309         result = SL_RESULT_PARAMETER_INVALID;
310     } else if ((0 == dataLength) && (0 == itemsLength)) {
311         // no data and no msg
312         SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
313         result = SL_RESULT_PARAMETER_INVALID;
314     // Note that a non-NULL data pointer with zero data length is allowed.
315     // We track that data pointer as it moves through the queue
316     // to assist the application in accounting for data buffers.
317     // A non-NULL items pointer with zero items length is also allowed, but has no value.
318     } else {
319         IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
320 
321         // buffer size check, can be done outside of lock because buffer type can't change
322         switch (thiz->mBufferType) {
323           case kAndroidBufferTypeMpeg2Ts:
324             if (dataLength % MPEG2_TS_PACKET_SIZE == 0) {
325                 // The downstream Stagefright MPEG-2 TS parser is sensitive to format errors,
326                 // so do a quick sanity check beforehand on the first packet of the buffer.
327                 // We don't check all the packets to avoid thrashing the data cache.
328                 if ((dataLength > 0) && (*(SLuint8 *)pData != MPEG2_TS_PACKET_SYNC)) {
329                     SL_LOGE("Error enqueueing MPEG-2 TS data: incorrect packet sync");
330                     result = SL_RESULT_CONTENT_CORRUPTED;
331                     SL_LEAVE_INTERFACE
332                 }
333                 break;
334             }
335             SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (packet size)",
336                     MPEG2_TS_PACKET_SIZE);
337             result = SL_RESULT_PARAMETER_INVALID;
338             SL_LEAVE_INTERFACE
339             break;
340           case kAndroidBufferTypeAacadts:
341             // zero dataLength is permitted in case of EOS command only
342             if (dataLength > 0) {
343                 result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(
344                     pData, dataLength);
345                 if (SL_RESULT_SUCCESS != result) {
346                     SL_LOGE("Error enqueueing ADTS data: data must start and end on frame "
347                             "boundaries");
348                     SL_LEAVE_INTERFACE
349                 }
350             }
351             break;
352           case kAndroidBufferTypeInvalid:
353           default:
354             result = SL_RESULT_PARAMETER_INVALID;
355             SL_LEAVE_INTERFACE
356         }
357 
358         interface_lock_exclusive(thiz);
359 
360         AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
361         if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
362             newRear = thiz->mBufferArray;
363         }
364         if (thiz->mEOS) {
365             SL_LOGE("Can't enqueue after EOS");
366             result = SL_RESULT_PRECONDITIONS_VIOLATED;
367         } else if (newRear == thiz->mFront) {
368             result = SL_RESULT_BUFFER_INSUFFICIENT;
369         } else {
370             // set oldRear->mItems based on items
371             result = setItems(dataLength, pItems, itemsLength, thiz->mBufferType, oldRear,
372                     &thiz->mEOS);
373             if (SL_RESULT_SUCCESS == result) {
374                 oldRear->mDataBuffer = pData;
375                 oldRear->mDataSize = dataLength;
376                 oldRear->mDataSizeConsumed = 0;
377                 oldRear->mBufferContext = pBufferContext;
378                 //oldRear->mBufferState = TBD;
379                 thiz->mRear = newRear;
380                 ++thiz->mState.count;
381             }
382         }
383         // set enqueue attribute if state is PLAYING and the first buffer is enqueued
384         interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
385                 (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
386                         ATTR_ABQ_ENQUEUE : ATTR_NONE);
387     }
388 
389     SL_LEAVE_INTERFACE
390 }
391 
392 
IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,SLAndroidBufferQueueState * pState)393 static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
394         SLAndroidBufferQueueState *pState)
395 {
396     SL_ENTER_INTERFACE
397 
398     // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
399 
400     if (NULL == pState) {
401         result = SL_RESULT_PARAMETER_INVALID;
402     } else {
403         IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
404 
405         interface_lock_shared(thiz);
406 
407         pState->count = thiz->mState.count;
408         pState->index = thiz->mState.index;
409 
410         interface_unlock_shared(thiz);
411 
412         result = SL_RESULT_SUCCESS;
413     }
414 
415     SL_LEAVE_INTERFACE
416 }
417 
418 
IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,SLuint32 eventFlags)419 static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,
420         SLuint32 eventFlags)
421 {
422     SL_ENTER_INTERFACE
423 
424     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
425     interface_lock_exclusive(thiz);
426     // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation
427     if (!(~(SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED /* | others TBD */ ) & eventFlags)) {
428         thiz->mCallbackEventsMask = eventFlags;
429         result = SL_RESULT_SUCCESS;
430     } else {
431         result = SL_RESULT_FEATURE_UNSUPPORTED;
432     }
433     interface_unlock_exclusive(thiz);
434 
435     SL_LEAVE_INTERFACE
436 }
437 
438 
IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,SLuint32 * pEventFlags)439 static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,
440         SLuint32 *pEventFlags)
441 {
442     SL_ENTER_INTERFACE
443 
444     if (NULL == pEventFlags) {
445         result = SL_RESULT_PARAMETER_INVALID;
446     } else {
447         IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
448         interface_lock_shared(thiz);
449         SLuint32 callbackEventsMask = thiz->mCallbackEventsMask;
450         interface_unlock_shared(thiz);
451         *pEventFlags = callbackEventsMask;
452         result = SL_RESULT_SUCCESS;
453     }
454 
455     SL_LEAVE_INTERFACE
456 }
457 
458 
459 static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = {
460     IAndroidBufferQueue_RegisterCallback,
461     IAndroidBufferQueue_Clear,
462     IAndroidBufferQueue_Enqueue,
463     IAndroidBufferQueue_GetState,
464     IAndroidBufferQueue_SetCallbackEventsMask,
465     IAndroidBufferQueue_GetCallbackEventsMask
466 };
467 
468 
IAndroidBufferQueue_init(void * self)469 void IAndroidBufferQueue_init(void *self)
470 {
471     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
472     thiz->mItf = &IAndroidBufferQueue_Itf;
473 
474     thiz->mState.count = 0;
475     thiz->mState.index = 0;
476 
477     thiz->mCallback = NULL;
478     thiz->mContext = NULL;
479     thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED;
480 
481     thiz->mBufferType = kAndroidBufferTypeInvalid;
482     thiz->mBufferArray = NULL;
483     thiz->mFront = NULL;
484     thiz->mRear = NULL;
485     thiz->mEOS = false;
486 }
487 
488 
IAndroidBufferQueue_deinit(void * self)489 void IAndroidBufferQueue_deinit(void *self)
490 {
491     IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
492     if (NULL != thiz->mBufferArray) {
493         free(thiz->mBufferArray);
494         thiz->mBufferArray = NULL;
495     }
496 }
497 
498 
499 #if 0
500 // Dump the contents of an IAndroidBufferQueue to the log.  This is for debugging only,
501 // and is not a documented API.  The associated object is locked throughout for atomicity,
502 // but the log entries may be interspersed with unrelated logs.
503 
504 void IAndroidBufferQueue_log(IAndroidBufferQueue *thiz)
505 {
506     interface_lock_shared(thiz);
507     SL_LOGI("IAndroidBufferQueue %p:", thiz);
508     SL_LOGI("  mState.count=%u mState.index=%u mCallback=%p mContext=%p",
509             thiz->mState.count, thiz->mState.index, thiz->mCallback, thiz->mContext);
510     const char *bufferTypeString;
511     switch (thiz->mBufferType) {
512     case kAndroidBufferTypeInvalid:
513         bufferTypeString = "kAndroidBufferTypeInvalid";
514         break;
515     case kAndroidBufferTypeMpeg2Ts:
516         bufferTypeString = "kAndroidBufferTypeMpeg2Ts";
517         break;
518     case kAndroidBufferTypeAacadts:
519         bufferTypeString = "kAndroidBufferTypeAacadts";
520         break;
521     default:
522         bufferTypeString = "unknown";
523         break;
524     }
525     SL_LOGI("  mCallbackEventsMask=0x%x, mBufferType=0x%x (%s), mEOS=%s",
526             thiz->mCallbackEventsMask,
527             thiz->mBufferType, bufferTypeString,
528             thiz->mEOS ? "true" : "false");
529     SL_LOGI("  mBufferArray=%p, mFront=%p (%u), mRear=%p (%u)",
530             thiz->mBufferArray,
531             thiz->mFront, thiz->mFront - thiz->mBufferArray,
532             thiz->mRear, thiz->mRear - thiz->mBufferArray);
533     SL_LOGI("  index mDataBuffer mDataSize mDataSizeConsumed mBufferContext mItems");
534     const AdvancedBufferHeader *hdr;
535     for (hdr = thiz->mFront; hdr != thiz->mRear; ) {
536         SLuint32 i = hdr - thiz->mBufferArray;
537         char itemString[32];
538         switch (thiz->mBufferType) {
539         case kAndroidBufferTypeMpeg2Ts:
540             switch (hdr->mItems.mTsCmdData.mTsCmdCode) {
541             case ANDROID_MP2TSEVENT_NONE:
542                 strcpy(itemString, "NONE");
543                 break;
544             case ANDROID_MP2TSEVENT_EOS:
545                 strcpy(itemString, "EOS");
546                 break;
547             case ANDROID_MP2TSEVENT_DISCONTINUITY:
548                 strcpy(itemString, "DISCONTINUITY");
549                 break;
550             case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
551                 snprintf(itemString, sizeof(itemString), "NEWPTS %llu",
552                         hdr->mItems.mTsCmdData.mPts);
553                 break;
554             case ANDROID_MP2TSEVENT_FORMAT_CHANGE:
555                 strcpy(itemString, "FORMAT_CHANGE");
556                 break;
557             default:
558                 snprintf(itemString, sizeof(itemString), "0x%x", hdr->mItems.mTsCmdData.mTsCmdCode);
559                 break;
560             }
561             break;
562         case kAndroidBufferTypeAacadts:
563             switch (hdr->mItems.mAdtsCmdData.mAdtsCmdCode) {
564             case ANDROID_ADTSEVENT_NONE:
565                 strcpy(itemString, "NONE");
566                 break;
567             case ANDROID_ADTSEVENT_EOS:
568                 strcpy(itemString, "EOS");
569                 break;
570             default:
571                 snprintf(itemString, sizeof(itemString), "0x%x",
572                         hdr->mItems.mAdtsCmdData.mAdtsCmdCode);
573                 break;
574             }
575             break;
576         default:
577             strcpy(itemString, "");
578             break;
579         }
580         SL_LOGI("  %5u %11p %9u %17u %14p %s",
581                 i, hdr->mDataBuffer, hdr->mDataSize, hdr->mDataSizeConsumed,
582                 hdr->mBufferContext, itemString);
583                 // mBufferState
584         if (++hdr == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
585             hdr = thiz->mBufferArray;
586         }
587     }
588     interface_unlock_shared(thiz);
589 }
590 
591 #endif
592