IAndroidBufferQueue.c revision af9b87de97356722370d11d2c5797d75cb43969e
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 audio recorder 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 void setItems(const SLAndroidBufferItem *pItems, SLuint32 itemsLength, 55 SLuint16 bufferType, AdvancedBufferHeader *pBuff) 56{ 57 // reset item structure based on type 58 switch (bufferType) { 59 case kAndroidBufferTypeMpeg2Ts: 60 pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE; 61 pBuff->mItems.mTsCmdData.mPts = 0; 62 break; 63 case kAndroidBufferTypeAacadts: 64 pBuff->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE; 65 break; 66 case kAndroidBufferTypeInvalid: 67 default: 68 // shouldn't happen, but just in case clear out the item structure 69 memset(&pBuff->mItems, 0, sizeof(AdvancedBufferItems)); 70 return; 71 } 72 73 // process all items in the array; if no items then we break out of loop immediately 74 while (itemsLength > 0) { 75 76 // remaining length must be large enough for one full item without any associated data 77 if (itemsLength < sizeof(SLAndroidBufferItem)) { 78 SL_LOGE("Partial item at end of array ignored"); 79 break; 80 } 81 itemsLength -= sizeof(SLAndroidBufferItem); 82 83 // remaining length must be large enough for data with current item and alignment padding 84 SLuint32 itemDataSizeWithAlignmentPadding = (pItems->itemSize + 3) & ~3; 85 if (itemsLength < itemDataSizeWithAlignmentPadding) { 86 SL_LOGE("Partial item data at end of array ignored"); 87 break; 88 } 89 itemsLength -= itemDataSizeWithAlignmentPadding; 90 91 // parse item data based on type 92 switch (bufferType) { 93 94 case kAndroidBufferTypeMpeg2Ts: { 95 switch (pItems->itemKey) { 96 97 case SL_ANDROID_ITEMKEY_EOS: 98 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS; 99 //SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode); 100 if (pItems->itemSize != 0) { 101 SL_LOGE("Invalid item parameter size %u for EOS, ignoring value", 102 pItems->itemSize); 103 } 104 break; 105 106 case SL_ANDROID_ITEMKEY_DISCONTINUITY: 107 if (pItems->itemSize == 0) { 108 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY; 109 //SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode); 110 } else if (pItems->itemSize == sizeof(SLAuint64)) { 111 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS; 112 pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData); 113 //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts); 114 } else { 115 SL_LOGE("Invalid item parameter size %u for MPEG-2 PTS, ignoring value", 116 pItems->itemSize); 117 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY; 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 ignored", pItems->itemKey, 151 pItems->itemSize); 152 break; 153 154 }// switch (pItems->itemKey) 155 } break; 156 157 case kAndroidBufferTypeAacadts: { 158 switch (pItems->itemKey) { 159 160 case SL_ANDROID_ITEMKEY_EOS: 161 pBuff->mItems.mAdtsCmdData.mAdtsCmdCode |= ANDROID_ADTSEVENT_EOS; 162 if (pItems->itemSize != 0) { 163 SL_LOGE("Invalid item parameter size %u for EOS, ignoring value", 164 pItems->itemSize); 165 } 166 break; 167 168 default: 169 // unknown item key 170 SL_LOGE("Unknown item key %u with size %u ignored", pItems->itemKey, 171 pItems->itemSize); 172 break; 173 174 }// switch (pItems->itemKey) 175 } break; 176 177 case kAndroidBufferTypeInvalid: 178 default: 179 // not reachable as we checked this earlier 180 return; 181 182 }// switch (bufferType) 183 184 // skip past this item, including data with alignment padding 185 pItems = (SLAndroidBufferItem *) ((char *) pItems + 186 sizeof(SLAndroidBufferItem) + itemDataSizeWithAlignmentPadding); 187 } 188 189 // now check for invalid combinations of items 190 switch (bufferType) { 191 192 case kAndroidBufferTypeMpeg2Ts: { 193 // supported Mpeg2Ts commands are mutually exclusive 194 switch (pBuff->mItems.mTsCmdData.mTsCmdCode) { 195 // single items are allowed 196 case ANDROID_MP2TSEVENT_NONE: 197 case ANDROID_MP2TSEVENT_EOS: 198 case ANDROID_MP2TSEVENT_DISCONTINUITY: 199 case ANDROID_MP2TSEVENT_DISCON_NEWPTS: 200 case ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL: 201 case ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO: 202 break; 203 // no combinations are allowed 204 default: 205 SL_LOGE("Invalid combination of items; all ignored"); 206 pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE; 207 break; 208 } 209 } break; 210 211 case kAndroidBufferTypeAacadts: { 212 // only one item supported, and thus no combination check needed 213 } break; 214 215 case kAndroidBufferTypeInvalid: 216 default: 217 // not reachable as we checked this earlier 218 return; 219 } 220 221} 222 223 224static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self, 225 slAndroidBufferQueueCallback callback, void *pContext) 226{ 227 SL_ENTER_INTERFACE 228 229 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 230 231 interface_lock_exclusive(thiz); 232 233 // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state 234 if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) { 235 thiz->mCallback = callback; 236 thiz->mContext = pContext; 237 238 // FIXME investigate why these two cases are not handled symmetrically any more 239 switch (InterfaceToObjectID(thiz)) { 240 case SL_OBJECTID_AUDIOPLAYER: 241 result = android_audioPlayer_androidBufferQueue_registerCallback_l( 242 (CAudioPlayer*) thiz->mThis); 243 break; 244 case XA_OBJECTID_MEDIAPLAYER: 245 result = SL_RESULT_SUCCESS; 246 break; 247 default: 248 result = SL_RESULT_PARAMETER_INVALID; 249 } 250 251 } else { 252 result = SL_RESULT_PRECONDITIONS_VIOLATED; 253 } 254 255 interface_unlock_exclusive(thiz); 256 257 SL_LEAVE_INTERFACE 258} 259 260 261static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self) 262{ 263 SL_ENTER_INTERFACE 264 result = SL_RESULT_SUCCESS; 265 266 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 267 268 interface_lock_exclusive(thiz); 269 270 // reset the queue pointers 271 thiz->mFront = &thiz->mBufferArray[0]; 272 thiz->mRear = &thiz->mBufferArray[0]; 273 // reset the queue state 274 thiz->mState.count = 0; 275 thiz->mState.index = 0; 276 // reset the individual buffers 277 for (XAuint16 i=0 ; i<(thiz->mNumBuffers + 1) ; i++) { 278 thiz->mBufferArray[i].mDataBuffer = NULL; 279 thiz->mBufferArray[i].mDataSize = 0; 280 thiz->mBufferArray[i].mDataSizeConsumed = 0; 281 thiz->mBufferArray[i].mBufferContext = NULL; 282 thiz->mBufferArray[i].mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE; 283 switch (thiz->mBufferType) { 284 case kAndroidBufferTypeMpeg2Ts: 285 thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE; 286 thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0; 287 break; 288 case kAndroidBufferTypeAacadts: 289 thiz->mBufferArray[i].mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE; 290 break; 291 default: 292 result = SL_RESULT_CONTENT_UNSUPPORTED; 293 } 294 } 295 296 if (SL_RESULT_SUCCESS == result) { 297 // object-specific behavior for a clear 298 switch (InterfaceToObjectID(thiz)) { 299 case SL_OBJECTID_AUDIOPLAYER: 300 result = SL_RESULT_SUCCESS; 301 android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis); 302 break; 303 case XA_OBJECTID_MEDIAPLAYER: 304 result = SL_RESULT_SUCCESS; 305 android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis); 306 break; 307 default: 308 result = SL_RESULT_PARAMETER_INVALID; 309 } 310 } 311 312 interface_unlock_exclusive(thiz); 313 314 SL_LEAVE_INTERFACE 315} 316 317 318static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self, 319 void *pBufferContext, 320 void *pData, 321 SLuint32 dataLength, 322 const SLAndroidBufferItem *pItems, 323 SLuint32 itemsLength) 324{ 325 SL_ENTER_INTERFACE 326 SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength); 327 328 if ((dataLength > 0) && (NULL == pData)) { 329 SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength); 330 result = SL_RESULT_PARAMETER_INVALID; 331 } else if ((itemsLength > 0) && (NULL == pItems)) { 332 SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength); 333 result = SL_RESULT_PARAMETER_INVALID; 334 } else if ((0 == dataLength) && (0 == itemsLength)) { 335 // no data and no msg 336 SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items."); 337 result = SL_RESULT_PARAMETER_INVALID; 338 // Note that a non-NULL data pointer with zero data length is allowed. 339 // We track that data pointer as it moves through the queue 340 // to assist the application in accounting for data buffers. 341 // A non-NULL items pointer with zero items length is also allowed, but has no value. 342 } else { 343 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 344 345 // buffer size check, can be done outside of lock because buffer type can't change 346 switch (thiz->mBufferType) { 347 case kAndroidBufferTypeMpeg2Ts: 348 if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) { 349 break; 350 } 351 SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)", 352 MPEG2_TS_BLOCK_SIZE); 353 result = SL_RESULT_PARAMETER_INVALID; 354 SL_LEAVE_INTERFACE 355 break; 356 case kAndroidBufferTypeAacadts: 357 // non-zero dataLength is permitted in case of EOS command only 358 if (dataLength > 0) { 359 result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries( 360 pData, dataLength); 361 if (SL_RESULT_SUCCESS != result) { 362 SL_LOGE("Error enqueueing ADTS data: data must start and end on frame " 363 "boundaries"); 364 SL_LEAVE_INTERFACE 365 } 366 } 367 break; 368 case kAndroidBufferTypeInvalid: 369 default: 370 result = SL_RESULT_PARAMETER_INVALID; 371 SL_LEAVE_INTERFACE 372 } 373 374 interface_lock_exclusive(thiz); 375 376 AdvancedBufferHeader *oldRear = thiz->mRear, *newRear; 377 if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) { 378 newRear = thiz->mBufferArray; 379 } 380 if (newRear == thiz->mFront) { 381 result = SL_RESULT_BUFFER_INSUFFICIENT; 382 } else { 383 oldRear->mDataBuffer = pData; 384 oldRear->mDataSize = dataLength; 385 oldRear->mDataSizeConsumed = 0; 386 oldRear->mBufferContext = pBufferContext; 387 oldRear->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE; 388 thiz->mRear = newRear; 389 ++thiz->mState.count; 390 // set oldRear->mItems based on items 391 setItems(pItems, itemsLength, thiz->mBufferType, oldRear); 392 result = SL_RESULT_SUCCESS; 393 } 394 // set enqueue attribute if state is PLAYING and the first buffer is enqueued 395 interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) && 396 (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ? 397 ATTR_ABQ_ENQUEUE : ATTR_NONE); 398 } 399 400 SL_LEAVE_INTERFACE 401} 402 403 404static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self, 405 SLAndroidBufferQueueState *pState) 406{ 407 SL_ENTER_INTERFACE 408 409 // Note that GetState while a Clear is pending is equivalent to GetState before the Clear 410 411 if (NULL == pState) { 412 result = SL_RESULT_PARAMETER_INVALID; 413 } else { 414 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 415 416 interface_lock_shared(thiz); 417 418 pState->count = thiz->mState.count; 419 pState->index = thiz->mState.index; 420 421 interface_unlock_shared(thiz); 422 423 result = SL_RESULT_SUCCESS; 424 } 425 426 SL_LEAVE_INTERFACE 427} 428 429 430static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self, 431 SLuint32 eventFlags) 432{ 433 SL_ENTER_INTERFACE 434 435 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 436 interface_lock_exclusive(thiz); 437 // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation 438 if ((SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED == eventFlags) || 439 (SL_ANDROIDBUFFERQUEUEEVENT_NONE == eventFlags)) { 440 thiz->mCallbackEventsMask = eventFlags; 441 result = SL_RESULT_SUCCESS; 442 } else { 443 result = SL_RESULT_FEATURE_UNSUPPORTED; 444 } 445 interface_unlock_exclusive(thiz); 446 447 SL_LEAVE_INTERFACE 448} 449 450 451static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self, 452 SLuint32 *pEventFlags) 453{ 454 SL_ENTER_INTERFACE 455 456 if (NULL == pEventFlags) { 457 result = SL_RESULT_PARAMETER_INVALID; 458 } else { 459 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 460 interface_lock_shared(thiz); 461 SLuint32 callbackEventsMask = thiz->mCallbackEventsMask; 462 interface_unlock_shared(thiz); 463 *pEventFlags = callbackEventsMask; 464 result = SL_RESULT_SUCCESS; 465 } 466 467 SL_LEAVE_INTERFACE 468} 469 470 471static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = { 472 IAndroidBufferQueue_RegisterCallback, 473 IAndroidBufferQueue_Clear, 474 IAndroidBufferQueue_Enqueue, 475 IAndroidBufferQueue_GetState, 476 IAndroidBufferQueue_SetCallbackEventsMask, 477 IAndroidBufferQueue_GetCallbackEventsMask 478}; 479 480 481void IAndroidBufferQueue_init(void *self) 482{ 483 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 484 thiz->mItf = &IAndroidBufferQueue_Itf; 485 486 thiz->mState.count = 0; 487 thiz->mState.index = 0; 488 489 thiz->mCallback = NULL; 490 thiz->mContext = NULL; 491 thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED; 492 493 thiz->mBufferType = kAndroidBufferTypeInvalid; 494 thiz->mBufferArray = NULL; 495 thiz->mFront = NULL; 496 thiz->mRear = NULL; 497} 498 499 500void IAndroidBufferQueue_deinit(void *self) 501{ 502 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 503 if (NULL != thiz->mBufferArray) { 504 free(thiz->mBufferArray); 505 thiz->mBufferArray = NULL; 506 } 507} 508