IAndroidBufferQueue.c revision e9236d046fdb5cac0696c42e03443a2439188146
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#include "sles_allinclusive.h"
20
21
22/**
23 * Determine the state of the audio player or audio recorder associated with a buffer queue.
24 *  Note that PLAYSTATE and RECORDSTATE values are equivalent (where PLAYING == RECORDING).
25 */
26
27static SLuint32 getAssociatedState(IAndroidBufferQueue *thiz)
28{
29    SLuint32 state;
30    switch (InterfaceToObjectID(thiz)) {
31      case XA_OBJECTID_MEDIAPLAYER:
32        state = ((CMediaPlayer *) thiz->mThis)->mPlay.mState;
33        break;
34      case SL_OBJECTID_AUDIOPLAYER:
35        state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState;
36        break;
37      case SL_OBJECTID_AUDIORECORDER:
38        state = ((CAudioRecorder *) thiz->mThis)->mRecord.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    if ((NULL == pItems) || (0 == itemsLength)) {
58        // no item data, 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 kAndroidBufferTypeInvalid:
65          default:
66            return;
67        }
68    } else {
69        // parse item data based on type
70        switch (bufferType) {
71
72          case kAndroidBufferTypeMpeg2Ts: {
73            SLuint32 index = 0;
74            // supported Mpeg2Ts commands are mutually exclusive
75            if (SL_ANDROID_ITEMKEY_EOS == pItems->itemKey) {
76                pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS;
77                //SL_LOGD("Found EOS event=%ld", pBuff->mItems.mTsCmdData.mTsCmdCode);
78            } else if (SL_ANDROID_ITEMKEY_DISCONTINUITY == pItems->itemKey) {
79                if (pItems->itemSize == 0) {
80                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
81                    //SL_LOGD("Found DISCONTINUITYevent=%ld", pBuff->mItems.mTsCmdData.mTsCmdCode);
82                } else if (pItems->itemSize == sizeof(SLAuint64)) {
83                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
84                    pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData);
85                    //SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts);
86                } else {
87                    SL_LOGE("Invalid size for MPEG-2 PTS, ignoring value");
88                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
89                }
90            } else {
91                pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
92            }
93            break;
94          }
95
96          default:
97            return;
98        }
99    }
100}
101
102
103static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,
104        slAndroidBufferQueueCallback callback, void *pContext)
105{
106    SL_ENTER_INTERFACE
107
108    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
109
110    interface_lock_exclusive(thiz);
111
112    // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
113    if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
114        thiz->mCallback = callback;
115        thiz->mContext = pContext;
116
117        switch (InterfaceToObjectID(thiz)) {
118          case SL_OBJECTID_AUDIOPLAYER:
119            result = SL_RESULT_SUCCESS;
120            android_audioPlayer_androidBufferQueue_registerCallback_l((CAudioPlayer*) thiz->mThis);
121            break;
122          case XA_OBJECTID_MEDIAPLAYER:
123            SL_LOGI("IAndroidBufferQueue_RegisterCallback()");
124            result = SL_RESULT_SUCCESS;
125            android_Player_androidBufferQueue_registerCallback_l((CMediaPlayer*) thiz->mThis);
126            break;
127          default:
128            result = SL_RESULT_PARAMETER_INVALID;
129        }
130
131    } else {
132        result = SL_RESULT_PRECONDITIONS_VIOLATED;
133    }
134
135    interface_unlock_exclusive(thiz);
136
137    SL_LEAVE_INTERFACE
138}
139
140
141static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)
142{
143    SL_ENTER_INTERFACE
144    result = SL_RESULT_SUCCESS;
145
146    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
147
148    interface_lock_exclusive(thiz);
149
150    // reset the queue pointers
151    thiz->mFront = &thiz->mBufferArray[0];
152    thiz->mRear = &thiz->mBufferArray[0];
153    // reset the queue state
154    thiz->mState.count = 0;
155    thiz->mState.index = 0;
156    // reset the individual buffers
157    for (XAuint16 i=0 ; i<(thiz->mNumBuffers + 1) ; i++) {
158        thiz->mBufferArray[i].mDataBuffer = NULL;
159        thiz->mBufferArray[i].mDataSize = 0;
160        thiz->mBufferArray[i].mDataSizeConsumed = 0;
161        thiz->mBufferArray[i].mBufferContext = NULL;
162        thiz->mBufferArray[i].mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
163        switch (thiz->mBufferType) {
164          case kAndroidBufferTypeMpeg2Ts:
165            thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
166            thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0;
167            break;
168          default:
169            result = SL_RESULT_CONTENT_UNSUPPORTED;
170        }
171    }
172
173    if (SL_RESULT_SUCCESS == result) {
174        // object-specific behavior for a clear
175        switch (InterfaceToObjectID(thiz)) {
176        case SL_OBJECTID_AUDIOPLAYER:
177            result = SL_RESULT_SUCCESS;
178            android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
179            break;
180        case XA_OBJECTID_MEDIAPLAYER:
181            result = SL_RESULT_SUCCESS;
182            android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
183            break;
184        default:
185            result = SL_RESULT_PARAMETER_INVALID;
186        }
187    }
188
189    interface_unlock_exclusive(thiz);
190
191    SL_LEAVE_INTERFACE
192}
193
194
195static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
196        void *pBufferContext,
197        void *pData,
198        SLuint32 dataLength,
199        const SLAndroidBufferItem *pItems,
200        SLuint32 itemsLength)
201{
202    SL_ENTER_INTERFACE
203
204    if ( ((NULL == pData) || (0 == dataLength))
205            && ((NULL == pItems) || (0 == itemsLength))) {
206        // no data and no msg
207        SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
208        result = SL_RESULT_PARAMETER_INVALID;
209    } else {
210        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
211
212        // buffer size check, can be done outside of lock because buffer type can't change
213        switch (thiz->mBufferType) {
214          case kAndroidBufferTypeMpeg2Ts:
215            if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) {
216                break;
217            }
218            // intended fall-through if test failed
219            SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)",
220                    MPEG2_TS_BLOCK_SIZE);
221          case kAndroidBufferTypeInvalid:
222          default:
223            result = SL_RESULT_PARAMETER_INVALID;
224            SL_LEAVE_INTERFACE
225        }
226
227        interface_lock_exclusive(thiz);
228
229        AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
230        if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
231            newRear = thiz->mBufferArray;
232        }
233        if (newRear == thiz->mFront) {
234            result = SL_RESULT_BUFFER_INSUFFICIENT;
235        } else {
236            oldRear->mDataBuffer = pData;
237            oldRear->mDataSize = dataLength;
238            oldRear->mDataSizeConsumed = 0;
239            oldRear->mBufferContext = pBufferContext;
240            oldRear->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
241            thiz->mRear = newRear;
242            ++thiz->mState.count;
243            setItems(pItems, itemsLength, thiz->mBufferType, oldRear);
244            result = SL_RESULT_SUCCESS;
245        }
246        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
247        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
248                (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
249                        ATTR_ABQ_ENQUEUE : ATTR_NONE);
250    }
251
252    SL_LEAVE_INTERFACE
253}
254
255
256static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
257        SLAndroidBufferQueueState *pState)
258{
259    SL_ENTER_INTERFACE
260
261    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
262
263    if (NULL == pState) {
264        result = SL_RESULT_PARAMETER_INVALID;
265    } else {
266        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
267
268        interface_lock_shared(thiz);
269
270        pState->count = thiz->mState.count;
271        pState->index = thiz->mState.index;
272
273        interface_unlock_shared(thiz);
274
275        result = SL_RESULT_SUCCESS;
276    }
277
278    SL_LEAVE_INTERFACE
279}
280
281
282static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,
283        SLuint32 eventFlags)
284{
285    SL_ENTER_INTERFACE
286
287    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
288    interface_lock_exclusive(thiz);
289    // FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation
290    if ((SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED == eventFlags) ||
291            (SL_ANDROIDBUFFERQUEUEEVENT_NONE == eventFlags)) {
292        thiz->mCallbackEventsMask = eventFlags;
293        result = SL_RESULT_SUCCESS;
294    } else {
295        result = SL_RESULT_FEATURE_UNSUPPORTED;
296    }
297    interface_unlock_exclusive(thiz);
298
299    SL_LEAVE_INTERFACE
300}
301
302
303static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,
304        SLuint32 *pEventFlags)
305{
306    SL_ENTER_INTERFACE
307
308    if (NULL == pEventFlags) {
309        result = SL_RESULT_PARAMETER_INVALID;
310    } else {
311        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
312        interface_lock_peek(thiz);
313        SLuint32 callbackEventsMask = thiz->mCallbackEventsMask;
314        interface_unlock_peek(thiz);
315        *pEventFlags = callbackEventsMask;
316        result = SL_RESULT_SUCCESS;
317    }
318
319    SL_LEAVE_INTERFACE
320}
321
322
323static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = {
324    IAndroidBufferQueue_RegisterCallback,
325    IAndroidBufferQueue_Clear,
326    IAndroidBufferQueue_Enqueue,
327    IAndroidBufferQueue_GetState,
328    IAndroidBufferQueue_SetCallbackEventsMask,
329    IAndroidBufferQueue_GetCallbackEventsMask
330};
331
332
333void IAndroidBufferQueue_init(void *self)
334{
335    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
336    thiz->mItf = &IAndroidBufferQueue_Itf;
337
338    thiz->mState.count = 0;
339    thiz->mState.index = 0;
340
341    thiz->mCallback = NULL;
342    thiz->mContext = NULL;
343    thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED;
344
345    thiz->mBufferType = kAndroidBufferTypeInvalid;
346    thiz->mBufferArray = NULL;
347    thiz->mFront = NULL;
348    thiz->mRear = NULL;
349}
350
351
352void IAndroidBufferQueue_deinit(void *self)
353{
354    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
355    if (NULL != thiz->mBufferArray) {
356        free(thiz->mBufferArray);
357        thiz->mBufferArray = NULL;
358    }
359}
360