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