IAndroidBufferQueue.c revision 70e6a0238597223221a8bf5e506c92acf28aa35f
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 result = SL_RESULT_SUCCESS; 218 219 } else { 220 result = SL_RESULT_PRECONDITIONS_VIOLATED; 221 } 222 223 interface_unlock_exclusive(thiz); 224 225 SL_LEAVE_INTERFACE 226} 227 228 229static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self) 230{ 231 SL_ENTER_INTERFACE 232 result = SL_RESULT_SUCCESS; 233 234 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 235 236 interface_lock_exclusive(thiz); 237 238 // reset the queue pointers 239 thiz->mFront = &thiz->mBufferArray[0]; 240 thiz->mRear = &thiz->mBufferArray[0]; 241 // reset the queue state 242 thiz->mState.count = 0; 243 thiz->mState.index = 0; 244 // reset the individual buffers 245 for (XAuint16 i=0 ; i<(thiz->mNumBuffers + 1) ; i++) { 246 thiz->mBufferArray[i].mDataBuffer = NULL; 247 thiz->mBufferArray[i].mDataSize = 0; 248 thiz->mBufferArray[i].mDataSizeConsumed = 0; 249 thiz->mBufferArray[i].mBufferContext = NULL; 250 thiz->mBufferArray[i].mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE; 251 switch (thiz->mBufferType) { 252 case kAndroidBufferTypeMpeg2Ts: 253 thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE; 254 thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0; 255 break; 256 case kAndroidBufferTypeAacadts: 257 thiz->mBufferArray[i].mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE; 258 break; 259 default: 260 result = SL_RESULT_CONTENT_UNSUPPORTED; 261 } 262 } 263 264 if (SL_RESULT_SUCCESS == result) { 265 // object-specific behavior for a clear 266 switch (InterfaceToObjectID(thiz)) { 267 case SL_OBJECTID_AUDIOPLAYER: 268 result = SL_RESULT_SUCCESS; 269 android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis); 270 break; 271 case XA_OBJECTID_MEDIAPLAYER: 272 result = SL_RESULT_SUCCESS; 273 android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis); 274 break; 275 default: 276 result = SL_RESULT_PARAMETER_INVALID; 277 } 278 } 279 280 interface_unlock_exclusive(thiz); 281 282 SL_LEAVE_INTERFACE 283} 284 285 286static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self, 287 void *pBufferContext, 288 void *pData, 289 SLuint32 dataLength, 290 const SLAndroidBufferItem *pItems, 291 SLuint32 itemsLength) 292{ 293 SL_ENTER_INTERFACE 294 SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength); 295 296 if ((dataLength > 0) && (NULL == pData)) { 297 SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength); 298 result = SL_RESULT_PARAMETER_INVALID; 299 } else if ((itemsLength > 0) && (NULL == pItems)) { 300 SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength); 301 result = SL_RESULT_PARAMETER_INVALID; 302 } else if ((0 == dataLength) && (0 == itemsLength)) { 303 // no data and no msg 304 SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items."); 305 result = SL_RESULT_PARAMETER_INVALID; 306 // Note that a non-NULL data pointer with zero data length is allowed. 307 // We track that data pointer as it moves through the queue 308 // to assist the application in accounting for data buffers. 309 // A non-NULL items pointer with zero items length is also allowed, but has no value. 310 } else { 311 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 312 313 // buffer size check, can be done outside of lock because buffer type can't change 314 switch (thiz->mBufferType) { 315 case kAndroidBufferTypeMpeg2Ts: 316 if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) { 317 break; 318 } 319 SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)", 320 MPEG2_TS_BLOCK_SIZE); 321 result = SL_RESULT_PARAMETER_INVALID; 322 SL_LEAVE_INTERFACE 323 break; 324 case kAndroidBufferTypeAacadts: 325 // non-zero dataLength is permitted in case of EOS command only 326 if (dataLength > 0) { 327 result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries( 328 pData, dataLength); 329 if (SL_RESULT_SUCCESS != result) { 330 SL_LOGE("Error enqueueing ADTS data: data must start and end on frame " 331 "boundaries"); 332 SL_LEAVE_INTERFACE 333 } 334 } 335 break; 336 case kAndroidBufferTypeInvalid: 337 default: 338 result = SL_RESULT_PARAMETER_INVALID; 339 SL_LEAVE_INTERFACE 340 } 341 342 interface_lock_exclusive(thiz); 343 344 AdvancedBufferHeader *oldRear = thiz->mRear, *newRear; 345 if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) { 346 newRear = thiz->mBufferArray; 347 } 348 if (newRear == thiz->mFront) { 349 result = SL_RESULT_BUFFER_INSUFFICIENT; 350 } else { 351 oldRear->mDataBuffer = pData; 352 oldRear->mDataSize = dataLength; 353 oldRear->mDataSizeConsumed = 0; 354 oldRear->mBufferContext = pBufferContext; 355 oldRear->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE; 356 thiz->mRear = newRear; 357 ++thiz->mState.count; 358 // set oldRear->mItems based on items 359 setItems(pItems, itemsLength, thiz->mBufferType, oldRear); 360 result = SL_RESULT_SUCCESS; 361 } 362 // set enqueue attribute if state is PLAYING and the first buffer is enqueued 363 interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) && 364 (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ? 365 ATTR_ABQ_ENQUEUE : ATTR_NONE); 366 } 367 368 SL_LEAVE_INTERFACE 369} 370 371 372static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self, 373 SLAndroidBufferQueueState *pState) 374{ 375 SL_ENTER_INTERFACE 376 377 // Note that GetState while a Clear is pending is equivalent to GetState before the Clear 378 379 if (NULL == pState) { 380 result = SL_RESULT_PARAMETER_INVALID; 381 } else { 382 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 383 384 interface_lock_shared(thiz); 385 386 pState->count = thiz->mState.count; 387 pState->index = thiz->mState.index; 388 389 interface_unlock_shared(thiz); 390 391 result = SL_RESULT_SUCCESS; 392 } 393 394 SL_LEAVE_INTERFACE 395} 396 397 398static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self, 399 SLuint32 eventFlags) 400{ 401 SL_ENTER_INTERFACE 402 403 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 404 interface_lock_exclusive(thiz); 405 // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation 406 if ((SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED == eventFlags) || 407 (SL_ANDROIDBUFFERQUEUEEVENT_NONE == 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} 466 467 468void IAndroidBufferQueue_deinit(void *self) 469{ 470 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 471 if (NULL != thiz->mBufferArray) { 472 free(thiz->mBufferArray); 473 thiz->mBufferArray = NULL; 474 } 475} 476