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