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