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