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