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    //SL_LOGV("IBufferQueue_Enqueue(%p, %p, %u)", self, pBuffer, size);
50
51    // Note that Enqueue while a Clear is pending is equivalent to Enqueue followed by Clear
52
53    if (NULL == pBuffer || 0 == size) {
54        result = SL_RESULT_PARAMETER_INVALID;
55    } else {
56        IBufferQueue *thiz = (IBufferQueue *) self;
57        interface_lock_exclusive(thiz);
58        BufferHeader *oldRear = thiz->mRear, *newRear;
59        if ((newRear = oldRear + 1) == &thiz->mArray[thiz->mNumBuffers + 1]) {
60            newRear = thiz->mArray;
61        }
62        if (newRear == thiz->mFront) {
63            result = SL_RESULT_BUFFER_INSUFFICIENT;
64        } else {
65            oldRear->mBuffer = pBuffer;
66            oldRear->mSize = size;
67            thiz->mRear = newRear;
68            ++thiz->mState.count;
69            result = SL_RESULT_SUCCESS;
70        }
71        // set enqueue attribute if state is PLAYING and the first buffer is enqueued
72        interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
73            (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
74            ATTR_BQ_ENQUEUE : ATTR_NONE);
75    }
76    SL_LEAVE_INTERFACE
77}
78
79
80SLresult IBufferQueue_Clear(SLBufferQueueItf self)
81{
82    SL_ENTER_INTERFACE
83
84    result = SL_RESULT_SUCCESS;
85    IBufferQueue *thiz = (IBufferQueue *) self;
86    interface_lock_exclusive(thiz);
87
88#ifdef ANDROID
89    if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
90        CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
91        // flush associated audio player
92        result = android_audioPlayer_bufferQueue_onClear(audioPlayer);
93        if (SL_RESULT_SUCCESS == result) {
94            thiz->mFront = &thiz->mArray[0];
95            thiz->mRear = &thiz->mArray[0];
96            thiz->mState.count = 0;
97            thiz->mState.playIndex = 0;
98            thiz->mSizeConsumed = 0;
99        }
100    }
101#endif
102
103#ifdef USE_OUTPUTMIXEXT
104    // mixer might be reading from the front buffer, so tread carefully here
105    // NTH asynchronous cancel instead of blocking until mixer acknowledges
106    thiz->mClearRequested = SL_BOOLEAN_TRUE;
107    do {
108        interface_cond_wait(thiz);
109    } while (thiz->mClearRequested);
110#endif
111
112    interface_unlock_exclusive(thiz);
113
114    SL_LEAVE_INTERFACE
115}
116
117
118static SLresult IBufferQueue_GetState(SLBufferQueueItf self, SLBufferQueueState *pState)
119{
120    SL_ENTER_INTERFACE
121
122    // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
123
124    if (NULL == pState) {
125        result = SL_RESULT_PARAMETER_INVALID;
126    } else {
127        IBufferQueue *thiz = (IBufferQueue *) self;
128        SLBufferQueueState state;
129        interface_lock_shared(thiz);
130#ifdef __cplusplus // FIXME Is this a compiler bug?
131        state.count = thiz->mState.count;
132        state.playIndex = thiz->mState.playIndex;
133#else
134        state = thiz->mState;
135#endif
136        interface_unlock_shared(thiz);
137        *pState = state;
138        result = SL_RESULT_SUCCESS;
139    }
140
141    SL_LEAVE_INTERFACE
142}
143
144
145SLresult IBufferQueue_RegisterCallback(SLBufferQueueItf self,
146    slBufferQueueCallback callback, void *pContext)
147{
148    SL_ENTER_INTERFACE
149
150    IBufferQueue *thiz = (IBufferQueue *) self;
151    interface_lock_exclusive(thiz);
152    // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
153    if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
154        thiz->mCallback = callback;
155        thiz->mContext = pContext;
156        result = SL_RESULT_SUCCESS;
157    } else {
158        result = SL_RESULT_PRECONDITIONS_VIOLATED;
159    }
160    interface_unlock_exclusive(thiz);
161
162    SL_LEAVE_INTERFACE
163}
164
165
166static const struct SLBufferQueueItf_ IBufferQueue_Itf = {
167    IBufferQueue_Enqueue,
168    IBufferQueue_Clear,
169    IBufferQueue_GetState,
170    IBufferQueue_RegisterCallback
171};
172
173void IBufferQueue_init(void *self)
174{
175    IBufferQueue *thiz = (IBufferQueue *) self;
176    thiz->mItf = &IBufferQueue_Itf;
177    thiz->mState.count = 0;
178    thiz->mState.playIndex = 0;
179    thiz->mCallback = NULL;
180    thiz->mContext = NULL;
181    thiz->mNumBuffers = 0;
182    thiz->mClearRequested = SL_BOOLEAN_FALSE;
183    thiz->mArray = NULL;
184    thiz->mFront = NULL;
185    thiz->mRear = NULL;
186#ifdef ANDROID
187    thiz->mSizeConsumed = 0;
188#endif
189    BufferHeader *bufferHeader = thiz->mTypical;
190    unsigned i;
191    for (i = 0; i < BUFFER_HEADER_TYPICAL+1; ++i, ++bufferHeader) {
192        bufferHeader->mBuffer = NULL;
193        bufferHeader->mSize = 0;
194    }
195}
196
197
198/** \brief Interface deinitialization hook called by IObject::Destroy.
199 *  Free the buffer queue, if it was larger than typical.
200 */
201
202void IBufferQueue_deinit(void *self)
203{
204    IBufferQueue *thiz = (IBufferQueue *) self;
205    if ((NULL != thiz->mArray) && (thiz->mArray != thiz->mTypical)) {
206        free(thiz->mArray);
207        thiz->mArray = NULL;
208    }
209}
210