IAndroidBufferQueue.c revision 677c76347d9aaca4cf3746b3dbfc8a741281066b
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      case SL_OBJECTID_AUDIORECORDER:
41        state = ((CAudioRecorder *) thiz->mThis)->mRecord.mState;
42        break;
43      default:
44        // unreachable, but just in case we will assume it is stopped
45        assert(SL_BOOLEAN_FALSE);
46        state = SL_PLAYSTATE_STOPPED;
47        break;
48    }
49    return state;
50}
51
52
53/**
54 * parse and set the items associated with the given buffer, based on the buffer type,
55 * which determines the set of authorized items and format
56 */
57static void setItems(const SLAndroidBufferItem *pItems, SLuint32 itemsLength,
58        SLuint16 bufferType, AdvancedBufferHeader *pBuff)
59{
60    // reset item structure based on type
61    switch (bufferType) {
62      case kAndroidBufferTypeMpeg2Ts:
63        pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
64        pBuff->mItems.mTsCmdData.mPts = 0;
65        break;
66      case kAndroidBufferTypeAacadts:
67        pBuff->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
68        break;
69      case kAndroidBufferTypeInvalid:
70      default:
71        // shouldn't happen, but just in case clear out the item structure
72        memset(&pBuff->mItems, 0, sizeof(AdvancedBufferItems));
73        return;
74    }
75
76    // process all items in the array; if no items then we break out of loop immediately
77    while (itemsLength > 0) {
78
79        // remaining length must be large enough for one full item without any associated data
80        if (itemsLength < sizeof(SLAndroidBufferItem)) {
81            SL_LOGE("Partial item at end of array ignored");
82            break;
83        }
84        itemsLength -= sizeof(SLAndroidBufferItem);
85
86        // remaining length must be large enough for data with current item and alignment padding
87        SLuint32 itemDataSizeWithAlignmentPadding = (pItems->itemSize + 3) & ~3;
88        if (itemsLength < itemDataSizeWithAlignmentPadding) {
89            SL_LOGE("Partial item data at end of array ignored");
90            break;
91        }
92        itemsLength -= itemDataSizeWithAlignmentPadding;
93
94        // parse item data based on type
95        switch (bufferType) {
96
97          case kAndroidBufferTypeMpeg2Ts: {
98            switch (pItems->itemKey) {
99
100              case SL_ANDROID_ITEMKEY_EOS:
101                pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS;
102                //SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
103                if (pItems->itemSize != 0) {
104                    SL_LOGE("Invalid item parameter size %u for EOS, ignoring value",
105                            pItems->itemSize);
106                }
107                break;
108
109              case SL_ANDROID_ITEMKEY_DISCONTINUITY:
110                if (pItems->itemSize == 0) {
111                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
112                    //SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
113                } else if (pItems->itemSize == sizeof(SLAuint64)) {
114                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
115                    pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData);
116                    //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts);
117                } else {
118                    SL_LOGE("Invalid item parameter size %u for MPEG-2 PTS, ignoring value",
119                            pItems->itemSize);
120                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
121                }
122                break;
123
124              case SL_ANDROID_ITEMKEY_FORMAT_CHANGE:
125                pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE;
126                if (pItems->itemSize != 0) {
127                    SL_LOGE("Invalid item parameter size %u for format change, ignoring value",
128                            pItems->itemSize);
129                }
130                break;
131
132              default:
133                // unknown item key
134                SL_LOGE("Unknown item key %u with size %u ignored", pItems->itemKey,
135                        pItems->itemSize);
136                break;
137
138            }// switch (pItems->itemKey)
139          } break;
140
141          case kAndroidBufferTypeAacadts: {
142            switch (pItems->itemKey) {
143
144              case SL_ANDROID_ITEMKEY_EOS:
145                pBuff->mItems.mAdtsCmdData.mAdtsCmdCode |= ANDROID_ADTSEVENT_EOS;
146                if (pItems->itemSize != 0) {
147                    SL_LOGE("Invalid item parameter size %u for EOS, ignoring value",
148                            pItems->itemSize);
149                }
150                break;
151
152              default:
153                // unknown item key
154                SL_LOGE("Unknown item key %u with size %u ignored", pItems->itemKey,
155                        pItems->itemSize);
156                break;
157
158            }// switch (pItems->itemKey)
159          } break;
160
161          case kAndroidBufferTypeInvalid:
162          default:
163            // not reachable as we checked this earlier
164            return;
165
166        }// switch (bufferType)
167
168        // skip past this item, including data with alignment padding
169        pItems = (SLAndroidBufferItem *) ((char *) pItems +
170                sizeof(SLAndroidBufferItem) + itemDataSizeWithAlignmentPadding);
171    }
172
173    // now check for invalid combinations of items
174    switch (bufferType) {
175
176      case kAndroidBufferTypeMpeg2Ts: {
177        // supported Mpeg2Ts commands are mutually exclusive
178        switch (pBuff->mItems.mTsCmdData.mTsCmdCode) {
179          // single items are allowed
180          case ANDROID_MP2TSEVENT_NONE:
181          case ANDROID_MP2TSEVENT_EOS:
182          case ANDROID_MP2TSEVENT_DISCONTINUITY:
183          case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
184          case ANDROID_MP2TSEVENT_FORMAT_CHANGE:
185            break;
186          // no combinations are allowed
187          default:
188            SL_LOGE("Invalid combination of items; all ignored");
189            pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
190            break;
191        }
192      } break;
193
194      case kAndroidBufferTypeAacadts: {
195        // only one item supported, and thus no combination check needed
196      } break;
197
198      case kAndroidBufferTypeInvalid:
199      default:
200        // not reachable as we checked this earlier
201        return;
202    }
203
204}
205
206
207static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,
208        slAndroidBufferQueueCallback callback, void *pContext)
209{
210    SL_ENTER_INTERFACE
211
212    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
213
214    interface_lock_exclusive(thiz);
215
216    // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
217    if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
218        thiz->mCallback = callback;
219        thiz->mContext = pContext;
220
221        switch (InterfaceToObjectID(thiz)) {
222          case SL_OBJECTID_AUDIOPLAYER:
223            result = android_audioPlayer_androidBufferQueue_registerCallback_l(
224                    (CAudioPlayer*) thiz->mThis);
225            break;
226          case XA_OBJECTID_MEDIAPLAYER:
227            SL_LOGV("IAndroidBufferQueue_RegisterCallback()");
228            result = SL_RESULT_SUCCESS;
229            //FIXME return error code
230            android_Player_androidBufferQueue_registerCallback_l((CMediaPlayer*) thiz->mThis);
231            break;
232          default:
233            result = SL_RESULT_PARAMETER_INVALID;
234        }
235
236    } else {
237        result = SL_RESULT_PRECONDITIONS_VIOLATED;
238    }
239
240    interface_unlock_exclusive(thiz);
241
242    SL_LEAVE_INTERFACE
243}
244
245
246static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)
247{
248    SL_ENTER_INTERFACE
249    result = SL_RESULT_SUCCESS;
250
251    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
252
253    interface_lock_exclusive(thiz);
254
255    // reset the queue pointers
256    thiz->mFront = &thiz->mBufferArray[0];
257    thiz->mRear = &thiz->mBufferArray[0];
258    // reset the queue state
259    thiz->mState.count = 0;
260    thiz->mState.index = 0;
261    // reset the individual buffers
262    for (XAuint16 i=0 ; i<(thiz->mNumBuffers + 1) ; i++) {
263        thiz->mBufferArray[i].mDataBuffer = NULL;
264        thiz->mBufferArray[i].mDataSize = 0;
265        thiz->mBufferArray[i].mDataSizeConsumed = 0;
266        thiz->mBufferArray[i].mBufferContext = NULL;
267        thiz->mBufferArray[i].mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
268        switch (thiz->mBufferType) {
269          case kAndroidBufferTypeMpeg2Ts:
270            thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
271            thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0;
272            break;
273          case kAndroidBufferTypeAacadts:
274            thiz->mBufferArray[i].mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
275            break;
276          default:
277            result = SL_RESULT_CONTENT_UNSUPPORTED;
278        }
279    }
280
281    if (SL_RESULT_SUCCESS == result) {
282        // object-specific behavior for a clear
283        switch (InterfaceToObjectID(thiz)) {
284        case SL_OBJECTID_AUDIOPLAYER:
285            result = SL_RESULT_SUCCESS;
286            android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
287            break;
288        case XA_OBJECTID_MEDIAPLAYER:
289            result = SL_RESULT_SUCCESS;
290            android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
291            break;
292        default:
293            result = SL_RESULT_PARAMETER_INVALID;
294        }
295    }
296
297    interface_unlock_exclusive(thiz);
298
299    SL_LEAVE_INTERFACE
300}
301
302
303static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
304        void *pBufferContext,
305        void *pData,
306        SLuint32 dataLength,
307        const SLAndroidBufferItem *pItems,
308        SLuint32 itemsLength)
309{
310    SL_ENTER_INTERFACE
311    SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength);
312
313    if ((dataLength > 0) && (NULL == pData)) {
314        SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength);
315        result = SL_RESULT_PARAMETER_INVALID;
316    } else if ((itemsLength > 0) && (NULL == pItems)) {
317        SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength);
318        result = SL_RESULT_PARAMETER_INVALID;
319    } else if ((0 == dataLength) && (0 == itemsLength)) {
320        // no data and no msg
321        SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
322        result = SL_RESULT_PARAMETER_INVALID;
323    // Note that a non-NULL data pointer with zero data length is allowed.
324    // We track that data pointer as it moves through the queue
325    // to assist the application in accounting for data buffers.
326    // A non-NULL items pointer with zero items length is also allowed, but has no value.
327    } else {
328        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
329
330        // buffer size check, can be done outside of lock because buffer type can't change
331        switch (thiz->mBufferType) {
332          case kAndroidBufferTypeMpeg2Ts:
333            if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) {
334                break;
335            }
336            SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)",
337                    MPEG2_TS_BLOCK_SIZE);
338            result = SL_RESULT_PARAMETER_INVALID;
339            SL_LEAVE_INTERFACE
340            break;
341          case kAndroidBufferTypeAacadts:
342            // non-zero dataLength is permitted in case of EOS command only
343            if (dataLength > 0) {
344                result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(
345                    pData, dataLength);
346                if (SL_RESULT_SUCCESS != result) {
347                    SL_LOGE("Error enqueueing ADTS data: data must start and end on frame "
348                            "boundaries");
349                    SL_LEAVE_INTERFACE
350                }
351            }
352            break;
353          case kAndroidBufferTypeInvalid:
354          default:
355            result = SL_RESULT_PARAMETER_INVALID;
356            SL_LEAVE_INTERFACE
357        }
358
359        interface_lock_exclusive(thiz);
360
361        AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
362        if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
363            newRear = thiz->mBufferArray;
364        }
365        if (newRear == thiz->mFront) {
366            result = SL_RESULT_BUFFER_INSUFFICIENT;
367        } else {
368            oldRear->mDataBuffer = pData;
369            oldRear->mDataSize = dataLength;
370            oldRear->mDataSizeConsumed = 0;
371            oldRear->mBufferContext = pBufferContext;
372            oldRear->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
373            thiz->mRear = newRear;
374            ++thiz->mState.count;
375            // set oldRear->mItems based on items
376            setItems(pItems, itemsLength, thiz->mBufferType, oldRear);
377            result = SL_RESULT_SUCCESS;
378        }
379        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
380        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
381                (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
382                        ATTR_ABQ_ENQUEUE : ATTR_NONE);
383    }
384
385    SL_LEAVE_INTERFACE
386}
387
388
389static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
390        SLAndroidBufferQueueState *pState)
391{
392    SL_ENTER_INTERFACE
393
394    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
395
396    if (NULL == pState) {
397        result = SL_RESULT_PARAMETER_INVALID;
398    } else {
399        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
400
401        interface_lock_shared(thiz);
402
403        pState->count = thiz->mState.count;
404        pState->index = thiz->mState.index;
405
406        interface_unlock_shared(thiz);
407
408        result = SL_RESULT_SUCCESS;
409    }
410
411    SL_LEAVE_INTERFACE
412}
413
414
415static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,
416        SLuint32 eventFlags)
417{
418    SL_ENTER_INTERFACE
419
420    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
421    interface_lock_exclusive(thiz);
422    // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation
423    if ((SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED == eventFlags) ||
424            (SL_ANDROIDBUFFERQUEUEEVENT_NONE == eventFlags)) {
425        thiz->mCallbackEventsMask = eventFlags;
426        result = SL_RESULT_SUCCESS;
427    } else {
428        result = SL_RESULT_FEATURE_UNSUPPORTED;
429    }
430    interface_unlock_exclusive(thiz);
431
432    SL_LEAVE_INTERFACE
433}
434
435
436static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,
437        SLuint32 *pEventFlags)
438{
439    SL_ENTER_INTERFACE
440
441    if (NULL == pEventFlags) {
442        result = SL_RESULT_PARAMETER_INVALID;
443    } else {
444        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
445        interface_lock_shared(thiz);
446        SLuint32 callbackEventsMask = thiz->mCallbackEventsMask;
447        interface_unlock_shared(thiz);
448        *pEventFlags = callbackEventsMask;
449        result = SL_RESULT_SUCCESS;
450    }
451
452    SL_LEAVE_INTERFACE
453}
454
455
456static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = {
457    IAndroidBufferQueue_RegisterCallback,
458    IAndroidBufferQueue_Clear,
459    IAndroidBufferQueue_Enqueue,
460    IAndroidBufferQueue_GetState,
461    IAndroidBufferQueue_SetCallbackEventsMask,
462    IAndroidBufferQueue_GetCallbackEventsMask
463};
464
465
466void IAndroidBufferQueue_init(void *self)
467{
468    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
469    thiz->mItf = &IAndroidBufferQueue_Itf;
470
471    thiz->mState.count = 0;
472    thiz->mState.index = 0;
473
474    thiz->mCallback = NULL;
475    thiz->mContext = NULL;
476    thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED;
477
478    thiz->mBufferType = kAndroidBufferTypeInvalid;
479    thiz->mBufferArray = NULL;
480    thiz->mFront = NULL;
481    thiz->mRear = NULL;
482}
483
484
485void IAndroidBufferQueue_deinit(void *self)
486{
487    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
488    if (NULL != thiz->mBufferArray) {
489        free(thiz->mBufferArray);
490        thiz->mBufferArray = NULL;
491    }
492}
493