IAndroidBufferQueue.c revision 6f0f5640d190b0187c356eb53bd96d9f9e49da60
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#include "sles_allinclusive.h" 20 21 22/** 23 * Determine the state of the audio player or audio recorder associated with a buffer queue. 24 * Note that PLAYSTATE and RECORDSTATE values are equivalent (where PLAYING == RECORDING). 25 */ 26 27static SLuint32 getAssociatedState(IAndroidBufferQueue *thiz) 28{ 29 SLuint32 state; 30 switch (InterfaceToObjectID(thiz)) { 31 case XA_OBJECTID_MEDIAPLAYER: 32 state = ((CMediaPlayer *) thiz->mThis)->mPlay.mState; 33 break; 34 case SL_OBJECTID_AUDIOPLAYER: 35 state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState; 36 break; 37 case SL_OBJECTID_AUDIORECORDER: 38 state = ((CAudioRecorder *) thiz->mThis)->mRecord.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 if ((NULL == pItems) || (0 == itemsLength)) { 58 // no item data, 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 kAndroidBufferTypeInvalid: 65 default: 66 return; 67 } 68 } else { 69 // parse item data based on type 70 switch (bufferType) { 71 72 case kAndroidBufferTypeMpeg2Ts: { 73 SLuint32 index = 0; 74 // supported Mpeg2Ts commands are mutually exclusive 75 switch (pItems->itemKey) { 76 77 case SL_ANDROID_ITEMKEY_EOS: 78 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS; 79 //SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode); 80 break; 81 82 case SL_ANDROID_ITEMKEY_DISCONTINUITY: 83 if (pItems->itemSize == 0) { 84 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY; 85 //SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode); 86 } else if (pItems->itemSize == sizeof(SLAuint64)) { 87 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS; 88 pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData); 89 //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts); 90 } else { 91 SL_LOGE("Invalid size for MPEG-2 PTS, ignoring value"); 92 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY; 93 } 94 break; 95 96 case SL_ANDROID_ITEMKEY_FORMAT_CHANGE: 97 pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE; 98 if (pItems->itemSize != 0) { 99 SL_LOGE("Invalid item parameter size for format change, ignoring value"); 100 } 101 break; 102 103 default: 104 // no event with this buffer 105 pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE; 106 break; 107 }// switch (pItems->itemKey) 108 } break; 109 110 default: 111 return; 112 }// switch (bufferType) 113 } 114} 115 116 117static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self, 118 slAndroidBufferQueueCallback callback, void *pContext) 119{ 120 SL_ENTER_INTERFACE 121 122 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 123 124 interface_lock_exclusive(thiz); 125 126 // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state 127 if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) { 128 thiz->mCallback = callback; 129 thiz->mContext = pContext; 130 131 switch (InterfaceToObjectID(thiz)) { 132 case SL_OBJECTID_AUDIOPLAYER: 133 result = SL_RESULT_SUCCESS; 134 android_audioPlayer_androidBufferQueue_registerCallback_l((CAudioPlayer*) thiz->mThis); 135 break; 136 case XA_OBJECTID_MEDIAPLAYER: 137 SL_LOGI("IAndroidBufferQueue_RegisterCallback()"); 138 result = SL_RESULT_SUCCESS; 139 android_Player_androidBufferQueue_registerCallback_l((CMediaPlayer*) thiz->mThis); 140 break; 141 default: 142 result = SL_RESULT_PARAMETER_INVALID; 143 } 144 145 } else { 146 result = SL_RESULT_PRECONDITIONS_VIOLATED; 147 } 148 149 interface_unlock_exclusive(thiz); 150 151 SL_LEAVE_INTERFACE 152} 153 154 155static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self) 156{ 157 SL_ENTER_INTERFACE 158 result = SL_RESULT_SUCCESS; 159 160 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 161 162 interface_lock_exclusive(thiz); 163 164 // reset the queue pointers 165 thiz->mFront = &thiz->mBufferArray[0]; 166 thiz->mRear = &thiz->mBufferArray[0]; 167 // reset the queue state 168 thiz->mState.count = 0; 169 thiz->mState.index = 0; 170 // reset the individual buffers 171 for (XAuint16 i=0 ; i<(thiz->mNumBuffers + 1) ; i++) { 172 thiz->mBufferArray[i].mDataBuffer = NULL; 173 thiz->mBufferArray[i].mDataSize = 0; 174 thiz->mBufferArray[i].mDataSizeConsumed = 0; 175 thiz->mBufferArray[i].mBufferContext = NULL; 176 thiz->mBufferArray[i].mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE; 177 switch (thiz->mBufferType) { 178 case kAndroidBufferTypeMpeg2Ts: 179 thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE; 180 thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0; 181 break; 182 default: 183 result = SL_RESULT_CONTENT_UNSUPPORTED; 184 } 185 } 186 187 if (SL_RESULT_SUCCESS == result) { 188 // object-specific behavior for a clear 189 switch (InterfaceToObjectID(thiz)) { 190 case SL_OBJECTID_AUDIOPLAYER: 191 result = SL_RESULT_SUCCESS; 192 android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis); 193 break; 194 case XA_OBJECTID_MEDIAPLAYER: 195 result = SL_RESULT_SUCCESS; 196 android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis); 197 break; 198 default: 199 result = SL_RESULT_PARAMETER_INVALID; 200 } 201 } 202 203 interface_unlock_exclusive(thiz); 204 205 SL_LEAVE_INTERFACE 206} 207 208 209static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self, 210 void *pBufferContext, 211 void *pData, 212 SLuint32 dataLength, 213 const SLAndroidBufferItem *pItems, 214 SLuint32 itemsLength) 215{ 216 SL_ENTER_INTERFACE 217 218 if ( ((NULL == pData) || (0 == dataLength)) 219 && ((NULL == pItems) || (0 == itemsLength))) { 220 // no data and no msg 221 SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items."); 222 result = SL_RESULT_PARAMETER_INVALID; 223 } else { 224 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 225 226 // buffer size check, can be done outside of lock because buffer type can't change 227 switch (thiz->mBufferType) { 228 case kAndroidBufferTypeMpeg2Ts: 229 if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) { 230 break; 231 } 232 // intended fall-through if test failed 233 SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)", 234 MPEG2_TS_BLOCK_SIZE); 235 case kAndroidBufferTypeInvalid: 236 default: 237 result = SL_RESULT_PARAMETER_INVALID; 238 SL_LEAVE_INTERFACE 239 } 240 241 interface_lock_exclusive(thiz); 242 243 AdvancedBufferHeader *oldRear = thiz->mRear, *newRear; 244 if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) { 245 newRear = thiz->mBufferArray; 246 } 247 if (newRear == thiz->mFront) { 248 result = SL_RESULT_BUFFER_INSUFFICIENT; 249 } else { 250 oldRear->mDataBuffer = pData; 251 oldRear->mDataSize = dataLength; 252 oldRear->mDataSizeConsumed = 0; 253 oldRear->mBufferContext = pBufferContext; 254 oldRear->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE; 255 thiz->mRear = newRear; 256 ++thiz->mState.count; 257 setItems(pItems, itemsLength, thiz->mBufferType, oldRear); 258 result = SL_RESULT_SUCCESS; 259 } 260 // set enqueue attribute if state is PLAYING and the first buffer is enqueued 261 interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) && 262 (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ? 263 ATTR_ABQ_ENQUEUE : ATTR_NONE); 264 } 265 266 SL_LEAVE_INTERFACE 267} 268 269 270static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self, 271 SLAndroidBufferQueueState *pState) 272{ 273 SL_ENTER_INTERFACE 274 275 // Note that GetState while a Clear is pending is equivalent to GetState before the Clear 276 277 if (NULL == pState) { 278 result = SL_RESULT_PARAMETER_INVALID; 279 } else { 280 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 281 282 interface_lock_shared(thiz); 283 284 pState->count = thiz->mState.count; 285 pState->index = thiz->mState.index; 286 287 interface_unlock_shared(thiz); 288 289 result = SL_RESULT_SUCCESS; 290 } 291 292 SL_LEAVE_INTERFACE 293} 294 295 296static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self, 297 SLuint32 eventFlags) 298{ 299 SL_ENTER_INTERFACE 300 301 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 302 interface_lock_exclusive(thiz); 303 // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation 304 if ((SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED == eventFlags) || 305 (SL_ANDROIDBUFFERQUEUEEVENT_NONE == eventFlags)) { 306 thiz->mCallbackEventsMask = eventFlags; 307 result = SL_RESULT_SUCCESS; 308 } else { 309 result = SL_RESULT_FEATURE_UNSUPPORTED; 310 } 311 interface_unlock_exclusive(thiz); 312 313 SL_LEAVE_INTERFACE 314} 315 316 317static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self, 318 SLuint32 *pEventFlags) 319{ 320 SL_ENTER_INTERFACE 321 322 if (NULL == pEventFlags) { 323 result = SL_RESULT_PARAMETER_INVALID; 324 } else { 325 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 326 interface_lock_peek(thiz); 327 SLuint32 callbackEventsMask = thiz->mCallbackEventsMask; 328 interface_unlock_peek(thiz); 329 *pEventFlags = callbackEventsMask; 330 result = SL_RESULT_SUCCESS; 331 } 332 333 SL_LEAVE_INTERFACE 334} 335 336 337static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = { 338 IAndroidBufferQueue_RegisterCallback, 339 IAndroidBufferQueue_Clear, 340 IAndroidBufferQueue_Enqueue, 341 IAndroidBufferQueue_GetState, 342 IAndroidBufferQueue_SetCallbackEventsMask, 343 IAndroidBufferQueue_GetCallbackEventsMask 344}; 345 346 347void IAndroidBufferQueue_init(void *self) 348{ 349 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 350 thiz->mItf = &IAndroidBufferQueue_Itf; 351 352 thiz->mState.count = 0; 353 thiz->mState.index = 0; 354 355 thiz->mCallback = NULL; 356 thiz->mContext = NULL; 357 thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED; 358 359 thiz->mBufferType = kAndroidBufferTypeInvalid; 360 thiz->mBufferArray = NULL; 361 thiz->mFront = NULL; 362 thiz->mRear = NULL; 363} 364 365 366void IAndroidBufferQueue_deinit(void *self) 367{ 368 IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self; 369 if (NULL != thiz->mBufferArray) { 370 free(thiz->mBufferArray); 371 thiz->mBufferArray = NULL; 372 } 373} 374