IAndroidBufferQueue.c revision 3ac5dcc05fe321e4f01918aef2e3e54e22c9a5c1
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                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
204static 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
241static 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
298static 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
384static 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
410static 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
431static 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
451static 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
461void 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
480void 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