Home | History | Annotate | Download | only in itf
      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 
     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  */
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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