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