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
getAssociatedState(IAndroidBufferQueue * thiz)30 static 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 */
setItems(const SLAndroidBufferItem * pItems,SLuint32 itemsLength,SLuint16 bufferType,AdvancedBufferHeader * pBuff)54 static 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
IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,slAndroidBufferQueueCallback callback,void * pContext)204 static 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
IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)241 static 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
IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,void * pBufferContext,void * pData,SLuint32 dataLength,const SLAndroidBufferItem * pItems,SLuint32 itemsLength)298 static 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
IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,SLAndroidBufferQueueState * pState)384 static 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
IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,SLuint32 eventFlags)410 static 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
IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,SLuint32 * pEventFlags)431 static 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
451 static 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
IAndroidBufferQueue_init(void * self)461 void 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
IAndroidBufferQueue_deinit(void * self)480 void 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