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
30static 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 */
54static 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
235static 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
260static 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
294static 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
393static 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
419static 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
439static 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
459static 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
469void 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
489void 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
504void 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