IAndroidBufferQueue.c revision 37dc2fccf3f122b79ebd554de209d0a3c94ae161
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(SLAint64)) {
83                    pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
84                    pBuff->mItems.mTsCmdData.mPts = *((SLAint64*)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
103SLresult 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
141SLresult 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        switch (thiz->mBufferType) {
163          case kAndroidBufferTypeMpeg2Ts:
164            thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
165            thiz->mBufferArray[i].mItems.mTsCmdData.mPts = 0;
166            break;
167          default:
168            result = SL_RESULT_CONTENT_UNSUPPORTED;
169        }
170    }
171
172    if (SL_RESULT_SUCCESS == result) {
173        // object-specific behavior for a clear
174        switch (InterfaceToObjectID(thiz)) {
175        case SL_OBJECTID_AUDIOPLAYER:
176            result = SL_RESULT_SUCCESS;
177            android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
178            break;
179        case XA_OBJECTID_MEDIAPLAYER:
180            result = SL_RESULT_SUCCESS;
181            android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
182            break;
183        default:
184            result = SL_RESULT_PARAMETER_INVALID;
185        }
186    }
187
188    interface_unlock_exclusive(thiz);
189
190    SL_LEAVE_INTERFACE
191}
192
193
194SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
195        void *pBufferContext,
196        void *pData,
197        SLuint32 dataLength,
198        const SLAndroidBufferItem *pItems,
199        SLuint32 itemsLength)
200{
201    SL_ENTER_INTERFACE
202
203    if ( ((NULL == pData) || (0 == dataLength))
204            && ((NULL == pItems) || (0 == itemsLength))) {
205        // no data and no msg
206        SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
207        result = SL_RESULT_PARAMETER_INVALID;
208    } else {
209        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
210
211        // buffer size check, can be done outside of lock because buffer type can't change
212        switch (thiz->mBufferType) {
213          case kAndroidBufferTypeMpeg2Ts:
214            if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) {
215                break;
216            }
217            // intended fall-through if test failed
218            SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)",
219                    MPEG2_TS_BLOCK_SIZE);
220          case kAndroidBufferTypeInvalid:
221          default:
222            result = SL_RESULT_PARAMETER_INVALID;
223            SL_LEAVE_INTERFACE
224        }
225
226        interface_lock_exclusive(thiz);
227
228        AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
229        if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
230            newRear = thiz->mBufferArray;
231        }
232        if (newRear == thiz->mFront) {
233            result = SL_RESULT_BUFFER_INSUFFICIENT;
234        } else {
235            oldRear->mDataBuffer = pData;
236            oldRear->mDataSize = dataLength;
237            oldRear->mDataSizeConsumed = 0;
238            oldRear->mBufferContext = pBufferContext;
239            thiz->mRear = newRear;
240            ++thiz->mState.count;
241            setItems(pItems, itemsLength, thiz->mBufferType, oldRear);
242            result = SL_RESULT_SUCCESS;
243        }
244        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
245        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
246                (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
247                        ATTR_ABQ_ENQUEUE : ATTR_NONE);
248    }
249
250    SL_LEAVE_INTERFACE
251}
252
253
254SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
255        SLAndroidBufferQueueState *pState)
256{
257    SL_ENTER_INTERFACE
258
259    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
260
261    if (NULL == pState) {
262        result = SL_RESULT_PARAMETER_INVALID;
263    } else {
264        IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
265
266        interface_lock_shared(thiz);
267
268        pState->count = thiz->mState.count;
269        pState->index = thiz->mState.index;
270
271        interface_unlock_shared(thiz);
272
273        result = SL_RESULT_SUCCESS;
274    }
275
276    SL_LEAVE_INTERFACE
277}
278
279
280static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = {
281    IAndroidBufferQueue_RegisterCallback,
282    IAndroidBufferQueue_Clear,
283    IAndroidBufferQueue_Enqueue,
284    IAndroidBufferQueue_GetState
285};
286
287
288void IAndroidBufferQueue_init(void *self)
289{
290    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
291    thiz->mItf = &IAndroidBufferQueue_Itf;
292
293    thiz->mState.count = 0;
294    thiz->mState.index = 0;
295
296    thiz->mCallback = NULL;
297    thiz->mContext = NULL;
298
299    thiz->mBufferType = kAndroidBufferTypeInvalid;
300    thiz->mBufferArray = NULL;
301    thiz->mFront = NULL;
302    thiz->mRear = NULL;
303}
304
305
306void IAndroidBufferQueue_deinit(void *self)
307{
308    IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
309    if (NULL != thiz->mBufferArray) {
310        free(thiz->mBufferArray);
311        thiz->mBufferArray = NULL;
312    }
313}
314