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     //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 
     80 SLresult 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 
    118 static 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 
    145 SLresult 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 
    166 static const struct SLBufferQueueItf_ IBufferQueue_Itf = {
    167     IBufferQueue_Enqueue,
    168     IBufferQueue_Clear,
    169     IBufferQueue_GetState,
    170     IBufferQueue_RegisterCallback
    171 };
    172 
    173 void 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 
    202 void 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