Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 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 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 21 | |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 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 | |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 26 | static SLuint32 getAssociatedState(IBufferQueue *thiz) |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 27 | { |
| 28 | SLuint32 state; |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 29 | switch (InterfaceToObjectID(thiz)) { |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 30 | case SL_OBJECTID_AUDIOPLAYER: |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 31 | state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 32 | break; |
| 33 | case SL_OBJECTID_AUDIORECORDER: |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 34 | state = ((CAudioRecorder *) thiz->mThis)->mRecord.mState; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 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 | |
Glenn Kasten | e5d006b | 2010-08-13 13:57:26 -0700 | [diff] [blame] | 46 | SLresult IBufferQueue_Enqueue(SLBufferQueueItf self, const void *pBuffer, SLuint32 size) |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 47 | { |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 48 | SL_ENTER_INTERFACE |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 49 | |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 50 | // Note that Enqueue while a Clear is pending is equivalent to Enqueue followed by Clear |
| 51 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 52 | if (NULL == pBuffer || 0 == size) { |
| 53 | result = SL_RESULT_PARAMETER_INVALID; |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 54 | } else { |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 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; |
Glenn Kasten | a3080da | 2010-09-21 14:49:48 -0700 | [diff] [blame] | 60 | } |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 61 | if (newRear == thiz->mFront) { |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 62 | result = SL_RESULT_BUFFER_INSUFFICIENT; |
| 63 | } else { |
| 64 | oldRear->mBuffer = pBuffer; |
| 65 | oldRear->mSize = size; |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 66 | thiz->mRear = newRear; |
| 67 | ++thiz->mState.count; |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 68 | result = SL_RESULT_SUCCESS; |
| 69 | } |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 70 | // set enqueue attribute if state is PLAYING and the first buffer is enqueued |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 71 | interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) && |
| 72 | (1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ? |
Jean-Michel Trivi | d158d31 | 2011-03-03 16:00:58 -0800 | [diff] [blame] | 73 | ATTR_BQ_ENQUEUE : ATTR_NONE); |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 74 | } |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 75 | SL_LEAVE_INTERFACE |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 76 | } |
| 77 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 78 | |
Glenn Kasten | e5d006b | 2010-08-13 13:57:26 -0700 | [diff] [blame] | 79 | SLresult IBufferQueue_Clear(SLBufferQueueItf self) |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 80 | { |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 81 | SL_ENTER_INTERFACE |
| 82 | |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 83 | result = SL_RESULT_SUCCESS; |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 84 | IBufferQueue *thiz = (IBufferQueue *) self; |
| 85 | interface_lock_exclusive(thiz); |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 86 | |
Jean-Michel Trivi | ef8931a | 2010-06-21 10:03:06 -0700 | [diff] [blame] | 87 | #ifdef ANDROID |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 88 | if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) { |
| 89 | CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 90 | // flush associated audio player |
Jean-Michel Trivi | 0ac71cb | 2010-09-29 12:55:40 -0700 | [diff] [blame] | 91 | result = android_audioPlayer_bufferQueue_onClear(audioPlayer); |
Andy Hung | d7fd688 | 2015-11-25 12:22:32 -0800 | [diff] [blame] | 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; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 101 | } |
Jean-Michel Trivi | 6a7bf77 | 2010-05-24 10:16:37 -0700 | [diff] [blame] | 102 | #endif |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 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 |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 107 | thiz->mClearRequested = SL_BOOLEAN_TRUE; |
Glenn Kasten | a3080da | 2010-09-21 14:49:48 -0700 | [diff] [blame] | 108 | do { |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 109 | interface_cond_wait(thiz); |
| 110 | } while (thiz->mClearRequested); |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 111 | #endif |
| 112 | |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 113 | interface_unlock_exclusive(thiz); |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 114 | |
Andy Hung | d7fd688 | 2015-11-25 12:22:32 -0800 | [diff] [blame] | 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. |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 118 | SL_LEAVE_INTERFACE |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 119 | } |
| 120 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 121 | |
| 122 | static SLresult IBufferQueue_GetState(SLBufferQueueItf self, SLBufferQueueState *pState) |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 123 | { |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 124 | SL_ENTER_INTERFACE |
| 125 | |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 126 | // Note that GetState while a Clear is pending is equivalent to GetState before the Clear |
| 127 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 128 | if (NULL == pState) { |
| 129 | result = SL_RESULT_PARAMETER_INVALID; |
| 130 | } else { |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 131 | IBufferQueue *thiz = (IBufferQueue *) self; |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 132 | SLBufferQueueState state; |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 133 | interface_lock_shared(thiz); |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 134 | #ifdef __cplusplus // FIXME Is this a compiler bug? |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 135 | state.count = thiz->mState.count; |
| 136 | state.playIndex = thiz->mState.playIndex; |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 137 | #else |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 138 | state = thiz->mState; |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 139 | #endif |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 140 | interface_unlock_shared(thiz); |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 141 | *pState = state; |
| 142 | result = SL_RESULT_SUCCESS; |
| 143 | } |
| 144 | |
| 145 | SL_LEAVE_INTERFACE |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 146 | } |
| 147 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 148 | |
Glenn Kasten | e5d006b | 2010-08-13 13:57:26 -0700 | [diff] [blame] | 149 | SLresult IBufferQueue_RegisterCallback(SLBufferQueueItf self, |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 150 | slBufferQueueCallback callback, void *pContext) |
| 151 | { |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 152 | SL_ENTER_INTERFACE |
| 153 | |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 154 | IBufferQueue *thiz = (IBufferQueue *) self; |
| 155 | interface_lock_exclusive(thiz); |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 156 | // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 157 | if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) { |
| 158 | thiz->mCallback = callback; |
| 159 | thiz->mContext = pContext; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 160 | result = SL_RESULT_SUCCESS; |
| 161 | } else { |
| 162 | result = SL_RESULT_PRECONDITIONS_VIOLATED; |
| 163 | } |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 164 | interface_unlock_exclusive(thiz); |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 165 | |
| 166 | SL_LEAVE_INTERFACE |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 167 | } |
| 168 | |
Glenn Kasten | ed46c29 | 2010-07-02 15:58:46 -0700 | [diff] [blame] | 169 | |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 170 | static const struct SLBufferQueueItf_ IBufferQueue_Itf = { |
| 171 | IBufferQueue_Enqueue, |
| 172 | IBufferQueue_Clear, |
| 173 | IBufferQueue_GetState, |
| 174 | IBufferQueue_RegisterCallback |
| 175 | }; |
| 176 | |
| 177 | void IBufferQueue_init(void *self) |
| 178 | { |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 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; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 190 | #ifdef ANDROID |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 191 | thiz->mSizeConsumed = 0; |
Raph Levien | 0f6da1a | 2014-11-14 13:51:32 -0800 | [diff] [blame] | 192 | thiz->mCallbackPending = false; |
Glenn Kasten | 4b65ef9 | 2010-07-16 17:37:20 -0700 | [diff] [blame] | 193 | #endif |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 194 | BufferHeader *bufferHeader = thiz->mTypical; |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 195 | unsigned i; |
| 196 | for (i = 0; i < BUFFER_HEADER_TYPICAL+1; ++i, ++bufferHeader) { |
| 197 | bufferHeader->mBuffer = NULL; |
| 198 | bufferHeader->mSize = 0; |
| 199 | } |
Glenn Kasten | 0b16726 | 2010-05-21 08:47:51 -0700 | [diff] [blame] | 200 | } |
Glenn Kasten | a3080da | 2010-09-21 14:49:48 -0700 | [diff] [blame] | 201 | |
| 202 | |
Glenn Kasten | a9a70a4 | 2010-10-05 07:46:26 -0700 | [diff] [blame] | 203 | /** \brief Interface deinitialization hook called by IObject::Destroy. |
| 204 | * Free the buffer queue, if it was larger than typical. |
| 205 | */ |
Glenn Kasten | a3080da | 2010-09-21 14:49:48 -0700 | [diff] [blame] | 206 | |
Glenn Kasten | a9a70a4 | 2010-10-05 07:46:26 -0700 | [diff] [blame] | 207 | void IBufferQueue_deinit(void *self) |
Glenn Kasten | a3080da | 2010-09-21 14:49:48 -0700 | [diff] [blame] | 208 | { |
Glenn Kasten | bcc5c72 | 2011-01-18 11:44:36 -0800 | [diff] [blame] | 209 | IBufferQueue *thiz = (IBufferQueue *) self; |
| 210 | if ((NULL != thiz->mArray) && (thiz->mArray != thiz->mTypical)) { |
| 211 | free(thiz->mArray); |
| 212 | thiz->mArray = NULL; |
Glenn Kasten | a3080da | 2010-09-21 14:49:48 -0700 | [diff] [blame] | 213 | } |
| 214 | } |