Home | History | Annotate | Download | only in itf
      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 
     26 static 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 
     46 SLresult 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 
     79 SLresult 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 
    122 static 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 
    149 SLresult 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 
    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 {
    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 
    207 void 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