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/* BufferQueue implementation */
18
19#include "sles_allinclusive.h"
20
21
22/** Determine the state of the audio player or audio recorder associated with a buffer queue.
23 *  Note that PLAYSTATE and RECORDSTATE values are equivalent (where PLAYING == RECORDING).
24 */
25
26static SLuint32 getAssociatedState(IBufferQueue *thiz)
27{
28    SLuint32 state;
29    switch (InterfaceToObjectID(thiz)) {
30    case SL_OBJECTID_AUDIOPLAYER:
31        state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState;
32        break;
33    case SL_OBJECTID_AUDIORECORDER:
34        state = ((CAudioRecorder *) thiz->mThis)->mRecord.mState;
35        break;
36    default:
37        // unreachable, but just in case we will assume it is stopped
38        assert(SL_BOOLEAN_FALSE);
39        state = SL_PLAYSTATE_STOPPED;
40        break;
41    }
42    return state;
43}
44
45
46SLresult IBufferQueue_Enqueue(SLBufferQueueItf self, const void *pBuffer, SLuint32 size)
47{
48    SL_ENTER_INTERFACE
49
50    // Note that Enqueue while a Clear is pending is equivalent to Enqueue followed by Clear
51
52    if (NULL == pBuffer || 0 == size) {
53        result = SL_RESULT_PARAMETER_INVALID;
54    } else {
55        IBufferQueue *thiz = (IBufferQueue *) self;
56        interface_lock_exclusive(thiz);
57        BufferHeader *oldRear = thiz->mRear, *newRear;
58        if ((newRear = oldRear + 1) == &thiz->mArray[thiz->mNumBuffers + 1]) {
59            newRear = thiz->mArray;
60        }
61        if (newRear == thiz->mFront) {
62            result = SL_RESULT_BUFFER_INSUFFICIENT;
63        } else {
64            oldRear->mBuffer = pBuffer;
65            oldRear->mSize = size;
66            thiz->mRear = newRear;
67            ++thiz->mState.count;
68            result = SL_RESULT_SUCCESS;
69        }
70        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
71        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
72            (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
73            ATTR_BQ_ENQUEUE : ATTR_NONE);
74    }
75    SL_LEAVE_INTERFACE
76}
77
78
79SLresult IBufferQueue_Clear(SLBufferQueueItf self)
80{
81    SL_ENTER_INTERFACE
82
83    result = SL_RESULT_SUCCESS;
84    IBufferQueue *thiz = (IBufferQueue *) self;
85    interface_lock_exclusive(thiz);
86
87#ifdef ANDROID
88    if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
89        CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
90        // flush associated audio player
91        result = android_audioPlayer_bufferQueue_onClear(audioPlayer);
92    }
93    // flush our buffers
94    if (SL_RESULT_SUCCESS == result) {
95        thiz->mFront = &thiz->mArray[0];
96        thiz->mRear = &thiz->mArray[0];
97        thiz->mState.count = 0;
98        thiz->mState.playIndex = 0;
99        thiz->mSizeConsumed = 0;
100        thiz->mCallbackPending = false;
101    }
102#endif
103
104#ifdef USE_OUTPUTMIXEXT
105    // mixer might be reading from the front buffer, so tread carefully here
106    // NTH asynchronous cancel instead of blocking until mixer acknowledges
107    thiz->mClearRequested = SL_BOOLEAN_TRUE;
108    do {
109        interface_cond_wait(thiz);
110    } while (thiz->mClearRequested);
111#endif
112
113    interface_unlock_exclusive(thiz);
114
115    // there is a danger that a buffer is still held by the callback thread
116    // after we leave IBufferQueue_Clear().  This buffer will not be written
117    // into anymore, but it is possible that it will be returned via callback.
118    SL_LEAVE_INTERFACE
119}
120
121
122static SLresult IBufferQueue_GetState(SLBufferQueueItf self, SLBufferQueueState *pState)
123{
124    SL_ENTER_INTERFACE
125
126    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
127
128    if (NULL == pState) {
129        result = SL_RESULT_PARAMETER_INVALID;
130    } else {
131        IBufferQueue *thiz = (IBufferQueue *) self;
132        SLBufferQueueState state;
133        interface_lock_shared(thiz);
134#ifdef __cplusplus // FIXME Is this a compiler bug?
135        state.count = thiz->mState.count;
136        state.playIndex = thiz->mState.playIndex;
137#else
138        state = thiz->mState;
139#endif
140        interface_unlock_shared(thiz);
141        *pState = state;
142        result = SL_RESULT_SUCCESS;
143    }
144
145    SL_LEAVE_INTERFACE
146}
147
148
149SLresult IBufferQueue_RegisterCallback(SLBufferQueueItf self,
150    slBufferQueueCallback callback, void *pContext)
151{
152    SL_ENTER_INTERFACE
153
154    IBufferQueue *thiz = (IBufferQueue *) self;
155    interface_lock_exclusive(thiz);
156    // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
157    if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
158        thiz->mCallback = callback;
159        thiz->mContext = pContext;
160        result = SL_RESULT_SUCCESS;
161    } else {
162        result = SL_RESULT_PRECONDITIONS_VIOLATED;
163    }
164    interface_unlock_exclusive(thiz);
165
166    SL_LEAVE_INTERFACE
167}
168
169
170static const struct SLBufferQueueItf_ IBufferQueue_Itf = {
171    IBufferQueue_Enqueue,
172    IBufferQueue_Clear,
173    IBufferQueue_GetState,
174    IBufferQueue_RegisterCallback
175};
176
177void IBufferQueue_init(void *self)
178{
179    IBufferQueue *thiz = (IBufferQueue *) self;
180    thiz->mItf = &IBufferQueue_Itf;
181    thiz->mState.count = 0;
182    thiz->mState.playIndex = 0;
183    thiz->mCallback = NULL;
184    thiz->mContext = NULL;
185    thiz->mNumBuffers = 0;
186    thiz->mClearRequested = SL_BOOLEAN_FALSE;
187    thiz->mArray = NULL;
188    thiz->mFront = NULL;
189    thiz->mRear = NULL;
190#ifdef ANDROID
191    thiz->mSizeConsumed = 0;
192    thiz->mCallbackPending = false;
193#endif
194    BufferHeader *bufferHeader = thiz->mTypical;
195    unsigned i;
196    for (i = 0; i < BUFFER_HEADER_TYPICAL+1; ++i, ++bufferHeader) {
197        bufferHeader->mBuffer = NULL;
198        bufferHeader->mSize = 0;
199    }
200}
201
202
203/** \brief Interface deinitialization hook called by IObject::Destroy.
204 *  Free the buffer queue, if it was larger than typical.
205 */
206
207void IBufferQueue_deinit(void *self)
208{
209    IBufferQueue *thiz = (IBufferQueue *) self;
210    if ((NULL != thiz->mArray) && (thiz->mArray != thiz->mTypical)) {
211        free(thiz->mArray);
212        thiz->mArray = NULL;
213    }
214}
215