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