IAndroidBufferQueue.c revision 682f9be91e641e80739c21d6ff124379a806182a
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 media player 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 SLresult setItems(SLuint32 dataLength,
55        const SLAndroidBufferItem *pItems, SLuint32 itemsLength,
56        SLuint16 bufferType, AdvancedBufferHeader *pBuff, bool *pEOS)
57{
58    // 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 kAndroidBufferTypeAacadts:
65        pBuff->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
66        break;
67      case kAndroidBufferTypeInvalid:
68      default:
69        // shouldn't happen, but just in case clear out the item structure
70        memset(&pBuff->mItems, 0, sizeof(AdvancedBufferItems));
71        return SL_RESULT_INTERNAL_ERROR;
72    }
73
74    // process all items in the array; if no items then we break out of loop immediately
75    while (itemsLength > 0) {
76
77        // remaining length must be large enough for one full item without any associated data
78        if (itemsLength < sizeof(SLAndroidBufferItem)) {
79            SL_LOGE("Partial item at end of array");
80            return SL_RESULT_PARAMETER_INVALID;
81        }
82        itemsLength -= sizeof(SLAndroidBufferItem);
83
84        // remaining length must be large enough for data with current item and alignment padding
85        SLuint32 itemDataSizeWithAlignmentPadding = (pItems->itemSize + 3) & ~3;
86        if (itemsLength < itemDataSizeWithAlignmentPadding) {
87            SL_LOGE("Partial item data at end of array");
88            return SL_RESULT_PARAMETER_INVALID;
89        }
90        itemsLength -= itemDataSizeWithAlignmentPadding;
91
92        // parse item data based on type
93        switch (bufferType) {
94
95          case kAndroidBufferTypeMpeg2Ts: {
96            switch (pItems->itemKey) {
97
98              case SL_ANDROID_ITEMKEY_EOS:
99                pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS;
100                //SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
101                if (pItems->itemSize != 0) {
102                    SL_LOGE("Invalid item parameter size %u for EOS", pItems->itemSize);
103                    return SL_RESULT_PARAMETER_INVALID;
104                }
105                break;
106
107              case SL_ANDROID_ITEMKEY_DISCONTINUITY:
108                if (pItems->itemSize == 0) {
109                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
110                    //SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
111                } else if (pItems->itemSize == sizeof(SLAuint64)) {
112                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
113                    pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData);
114                    //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts);
115                } else {
116                    SL_LOGE("Invalid item parameter size %u for MPEG-2 PTS", pItems->itemSize);
117                    return SL_RESULT_PARAMETER_INVALID;
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", pItems->itemSize);
125                    return SL_RESULT_PARAMETER_INVALID;
126                }
127                break;
128
129              default:
130                // unknown item key
131                SL_LOGE("Unknown item key %u with size %u", pItems->itemKey, pItems->itemSize);
132                return SL_RESULT_PARAMETER_INVALID;
133
134            }// switch (pItems->itemKey)
135          } break;
136
137          case kAndroidBufferTypeAacadts: {
138            switch (pItems->itemKey) {
139
140              case SL_ANDROID_ITEMKEY_EOS:
141                pBuff->mItems.mAdtsCmdData.mAdtsCmdCode |= ANDROID_ADTSEVENT_EOS;
142                if (pItems->itemSize != 0) {
143                    SL_LOGE("Invalid item parameter size %u for EOS", pItems->itemSize);
144                    return SL_RESULT_PARAMETER_INVALID;
145                }
146                break;
147
148              default:
149                // unknown item key
150                SL_LOGE("Unknown item key %u with size %u", pItems->itemKey, pItems->itemSize);
151                return SL_RESULT_PARAMETER_INVALID;
152
153            }// switch (pItems->itemKey)
154          } break;
155
156          case kAndroidBufferTypeInvalid:
157          default:
158            // not reachable as we checked this earlier
159            return SL_RESULT_INTERNAL_ERROR;
160
161        }// switch (bufferType)
162
163        // skip past this item, including data with alignment padding
164        pItems = (SLAndroidBufferItem *) ((char *) pItems +
165                sizeof(SLAndroidBufferItem) + itemDataSizeWithAlignmentPadding);
166    }
167
168    // now check for invalid combinations of items
169    switch (bufferType) {
170
171      case kAndroidBufferTypeMpeg2Ts: {
172        // supported Mpeg2Ts commands are mutually exclusive
173        switch (pBuff->mItems.mTsCmdData.mTsCmdCode) {
174          // single items are allowed
175          case ANDROID_MP2TSEVENT_EOS:
176            if (dataLength > 0) {
177                SL_LOGE("Can't enqueue non-zero data with EOS");
178                return SL_RESULT_PRECONDITIONS_VIOLATED;
179            }
180            *pEOS = true;
181            break;
182          case ANDROID_MP2TSEVENT_NONE:
183          case ANDROID_MP2TSEVENT_DISCONTINUITY:
184          case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
185          case ANDROID_MP2TSEVENT_FORMAT_CHANGE:
186            break;
187          // no combinations are allowed
188          default:
189            SL_LOGE("Invalid combination of items");
190            return SL_RESULT_PARAMETER_INVALID;
191        }
192      } break;
193
194      case kAndroidBufferTypeAacadts: {
195        // only one item supported, and thus no combination check needed
196        if (pBuff->mItems.mAdtsCmdData.mAdtsCmdCode == ANDROID_ADTSEVENT_EOS) {
197            if (dataLength > 0) {
198                SL_LOGE("Can't enqueue non-zero data with EOS");
199                return SL_RESULT_PRECONDITIONS_VIOLATED;
200            }
201            *pEOS = true;
202        }
203      } break;
204
205      case kAndroidBufferTypeInvalid:
206      default:
207        // not reachable as we checked this earlier
208        return SL_RESULT_INTERNAL_ERROR;
209    }
210
211    return SL_RESULT_SUCCESS;
212}
213
214
215static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,
216        slAndroidBufferQueueCallback callback, void *pContext)
217{
218    SL_ENTER_INTERFACE
219
220    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
221
222    interface_lock_exclusive(thiz);
223
224    // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
225    if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
226        thiz->mCallback = callback;
227        thiz->mContext = pContext;
228        result = SL_RESULT_SUCCESS;
229
230    } else {
231        result = SL_RESULT_PRECONDITIONS_VIOLATED;
232    }
233
234    interface_unlock_exclusive(thiz);
235
236    SL_LEAVE_INTERFACE
237}
238
239
240static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)
241{
242    SL_ENTER_INTERFACE
243    result = SL_RESULT_SUCCESS;
244
245    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
246
247    interface_lock_exclusive(thiz);
248
249    // reset the queue pointers
250    thiz->mFront = &thiz->mBufferArray[0];
251    thiz->mRear = &thiz->mBufferArray[0];
252    // reset the queue state
253    thiz->mState.count = 0;
254    thiz->mState.index = 0;
255
256    // object-specific behavior for a clear
257    switch (InterfaceToObjectID(thiz)) {
258    case SL_OBJECTID_AUDIOPLAYER:
259        android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
260        break;
261    case XA_OBJECTID_MEDIAPLAYER:
262        android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
263        break;
264    default:
265        result = SL_RESULT_PARAMETER_INVALID;
266    }
267
268    interface_unlock_exclusive(thiz);
269
270    SL_LEAVE_INTERFACE
271}
272
273
274static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
275        void *pBufferContext,
276        void *pData,
277        SLuint32 dataLength,
278        const SLAndroidBufferItem *pItems,
279        SLuint32 itemsLength)
280{
281    SL_ENTER_INTERFACE
282    SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength);
283
284    if ((dataLength > 0) && (NULL == pData)) {
285        SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength);
286        result = SL_RESULT_PARAMETER_INVALID;
287    } else if ((itemsLength > 0) && (NULL == pItems)) {
288        SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength);
289        result = SL_RESULT_PARAMETER_INVALID;
290    } else if ((0 == dataLength) && (0 == itemsLength)) {
291        // no data and no msg
292        SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
293        result = SL_RESULT_PARAMETER_INVALID;
294    // Note that a non-NULL data pointer with zero data length is allowed.
295    // We track that data pointer as it moves through the queue
296    // to assist the application in accounting for data buffers.
297    // A non-NULL items pointer with zero items length is also allowed, but has no value.
298    } else {
299        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
300
301        // buffer size check, can be done outside of lock because buffer type can't change
302        switch (thiz->mBufferType) {
303          case kAndroidBufferTypeMpeg2Ts:
304            if (dataLength % MPEG2_TS_PACKET_SIZE == 0) {
305                // The downstream Stagefright MPEG-2 TS parser is sensitive to format errors,
306                // so do a quick sanity check beforehand on the first packet of the buffer.
307                // We don't check all the packets to avoid thrashing the data cache.
308                if ((dataLength > 0) && (*(SLuint8 *)pData != MPEG2_TS_PACKET_SYNC)) {
309                    SL_LOGE("Error enqueueing MPEG-2 TS data: incorrect packet sync");
310                    result = SL_RESULT_CONTENT_CORRUPTED;
311                    SL_LEAVE_INTERFACE
312                }
313                break;
314            }
315            SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (packet size)",
316                    MPEG2_TS_PACKET_SIZE);
317            result = SL_RESULT_PARAMETER_INVALID;
318            SL_LEAVE_INTERFACE
319            break;
320          case kAndroidBufferTypeAacadts:
321            // zero dataLength is permitted in case of EOS command only
322            if (dataLength > 0) {
323                result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(
324                    pData, dataLength);
325                if (SL_RESULT_SUCCESS != result) {
326                    SL_LOGE("Error enqueueing ADTS data: data must start and end on frame "
327                            "boundaries");
328                    SL_LEAVE_INTERFACE
329                }
330            }
331            break;
332          case kAndroidBufferTypeInvalid:
333          default:
334            result = SL_RESULT_PARAMETER_INVALID;
335            SL_LEAVE_INTERFACE
336        }
337
338        interface_lock_exclusive(thiz);
339
340        AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
341        if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
342            newRear = thiz->mBufferArray;
343        }
344        if (thiz->mEOS) {
345            SL_LOGE("Can't enqueue after EOS");
346            result = SL_RESULT_PRECONDITIONS_VIOLATED;
347        } else if (newRear == thiz->mFront) {
348            result = SL_RESULT_BUFFER_INSUFFICIENT;
349        } else {
350            // set oldRear->mItems based on items
351            result = setItems(dataLength, pItems, itemsLength, thiz->mBufferType, oldRear,
352                    &thiz->mEOS);
353            if (SL_RESULT_SUCCESS == result) {
354                oldRear->mDataBuffer = pData;
355                oldRear->mDataSize = dataLength;
356                oldRear->mDataSizeConsumed = 0;
357                oldRear->mBufferContext = pBufferContext;
358                //oldRear->mBufferState = TBD;
359                thiz->mRear = newRear;
360                ++thiz->mState.count;
361            }
362        }
363        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
364        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
365                (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
366                        ATTR_ABQ_ENQUEUE : ATTR_NONE);
367    }
368
369    SL_LEAVE_INTERFACE
370}
371
372
373static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
374        SLAndroidBufferQueueState *pState)
375{
376    SL_ENTER_INTERFACE
377
378    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
379
380    if (NULL == pState) {
381        result = SL_RESULT_PARAMETER_INVALID;
382    } else {
383        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
384
385        interface_lock_shared(thiz);
386
387        pState->count = thiz->mState.count;
388        pState->index = thiz->mState.index;
389
390        interface_unlock_shared(thiz);
391
392        result = SL_RESULT_SUCCESS;
393    }
394
395    SL_LEAVE_INTERFACE
396}
397
398
399static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,
400        SLuint32 eventFlags)
401{
402    SL_ENTER_INTERFACE
403
404    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
405    interface_lock_exclusive(thiz);
406    // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation
407    if (!(~(SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED /* | others TBD */ ) & 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    thiz->mEOS = false;
466}
467
468
469void IAndroidBufferQueue_deinit(void *self)
470{
471    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
472    if (NULL != thiz->mBufferArray) {
473        free(thiz->mBufferArray);
474        thiz->mBufferArray = NULL;
475    }
476}
477
478
479#if 0
480// Dump the contents of an IAndroidBufferQueue to the log.  This is for debugging only,
481// and is not a documented API.  The associated object is locked throughout for atomicity,
482// but the log entries may be interspersed with unrelated logs.
483
484void IAndroidBufferQueue_log(IAndroidBufferQueue *thiz)
485{
486    interface_lock_shared(thiz);
487    SL_LOGI("IAndroidBufferQueue %p:", thiz);
488    SL_LOGI("  mState.count=%u mState.index=%u mCallback=%p mContext=%p",
489            thiz->mState.count, thiz->mState.index, thiz->mCallback, thiz->mContext);
490    const char *bufferTypeString;
491    switch (thiz->mBufferType) {
492    case kAndroidBufferTypeInvalid:
493        bufferTypeString = "kAndroidBufferTypeInvalid";
494        break;
495    case kAndroidBufferTypeMpeg2Ts:
496        bufferTypeString = "kAndroidBufferTypeMpeg2Ts";
497        break;
498    case kAndroidBufferTypeAacadts:
499        bufferTypeString = "kAndroidBufferTypeAacadts";
500        break;
501    default:
502        bufferTypeString = "unknown";
503        break;
504    }
505    SL_LOGI("  mCallbackEventsMask=0x%x, mBufferType=0x%x (%s), mEOS=%s",
506            thiz->mCallbackEventsMask,
507            thiz->mBufferType, bufferTypeString,
508            thiz->mEOS ? "true" : "false");
509    SL_LOGI("  mBufferArray=%p, mFront=%p (%u), mRear=%p (%u)",
510            thiz->mBufferArray,
511            thiz->mFront, thiz->mFront - thiz->mBufferArray,
512            thiz->mRear, thiz->mRear - thiz->mBufferArray);
513    SL_LOGI("  index mDataBuffer mDataSize mDataSizeConsumed mBufferContext mItems");
514    const AdvancedBufferHeader *hdr;
515    for (hdr = thiz->mFront; hdr != thiz->mRear; ) {
516        SLuint32 i = hdr - thiz->mBufferArray;
517        char itemString[32];
518        switch (thiz->mBufferType) {
519        case kAndroidBufferTypeMpeg2Ts:
520            switch (hdr->mItems.mTsCmdData.mTsCmdCode) {
521            case ANDROID_MP2TSEVENT_NONE:
522                strcpy(itemString, "NONE");
523                break;
524            case ANDROID_MP2TSEVENT_EOS:
525                strcpy(itemString, "EOS");
526                break;
527            case ANDROID_MP2TSEVENT_DISCONTINUITY:
528                strcpy(itemString, "DISCONTINUITY");
529                break;
530            case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
531                snprintf(itemString, sizeof(itemString), "NEWPTS %llu",
532                        hdr->mItems.mTsCmdData.mPts);
533                break;
534            case ANDROID_MP2TSEVENT_FORMAT_CHANGE:
535                strcpy(itemString, "FORMAT_CHANGE");
536                break;
537            default:
538                snprintf(itemString, sizeof(itemString), "0x%x", hdr->mItems.mTsCmdData.mTsCmdCode);
539                break;
540            }
541            break;
542        case kAndroidBufferTypeAacadts:
543            switch (hdr->mItems.mAdtsCmdData.mAdtsCmdCode) {
544            case ANDROID_ADTSEVENT_NONE:
545                strcpy(itemString, "NONE");
546                break;
547            case ANDROID_ADTSEVENT_EOS:
548                strcpy(itemString, "EOS");
549                break;
550            default:
551                snprintf(itemString, sizeof(itemString), "0x%x",
552                        hdr->mItems.mAdtsCmdData.mAdtsCmdCode);
553                break;
554            }
555            break;
556        default:
557            strcpy(itemString, "");
558            break;
559        }
560        SL_LOGI("  %5u %11p %9u %17u %14p %s",
561                i, hdr->mDataBuffer, hdr->mDataSize, hdr->mDataSizeConsumed,
562                hdr->mBufferContext, itemString);
563                // mBufferState
564        if (++hdr == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
565            hdr = thiz->mBufferArray;
566        }
567    }
568    interface_unlock_shared(thiz);
569}
570
571#endif
572