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             thiz->mCallbackPending = false;
    100         }
    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     SL_LEAVE_INTERFACE
    116 }
    117 
    118 
    119 static SLresult IBufferQueue_GetState(SLBufferQueueItf self, SLBufferQueueState *pState)
    120 {
    121     SL_ENTER_INTERFACE
    122 
    123     // Note that GetState while a Clear is pending is equivalent to GetState before the Clear
    124 
    125     if (NULL == pState) {
    126         result = SL_RESULT_PARAMETER_INVALID;
    127     } else {
    128         IBufferQueue *thiz = (IBufferQueue *) self;
    129         SLBufferQueueState state;
    130         interface_lock_shared(thiz);
    131 #ifdef __cplusplus // FIXME Is this a compiler bug?
    132         state.count = thiz->mState.count;
    133         state.playIndex = thiz->mState.playIndex;
    134 #else
    135         state = thiz->mState;
    136 #endif
    137         interface_unlock_shared(thiz);
    138         *pState = state;
    139         result = SL_RESULT_SUCCESS;
    140     }
    141 
    142     SL_LEAVE_INTERFACE
    143 }
    144 
    145 
    146 SLresult IBufferQueue_RegisterCallback(SLBufferQueueItf self,
    147     slBufferQueueCallback callback, void *pContext)
    148 {
    149     SL_ENTER_INTERFACE
    150 
    151     IBufferQueue *thiz = (IBufferQueue *) self;
    152     interface_lock_exclusive(thiz);
    153     // verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
    154     if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
    155         thiz->mCallback = callback;
    156         thiz->mContext = pContext;
    157         result = SL_RESULT_SUCCESS;
    158     } else {
    159         result = SL_RESULT_PRECONDITIONS_VIOLATED;
    160     }
    161     interface_unlock_exclusive(thiz);
    162 
    163     SL_LEAVE_INTERFACE
    164 }
    165 
    166 
    167 static const struct SLBufferQueueItf_ IBufferQueue_Itf = {
    168     IBufferQueue_Enqueue,
    169     IBufferQueue_Clear,
    170     IBufferQueue_GetState,
    171     IBufferQueue_RegisterCallback
    172 };
    173 
    174 void IBufferQueue_init(void *self)
    175 {
    176     IBufferQueue *thiz = (IBufferQueue *) self;
    177     thiz->mItf = &IBufferQueue_Itf;
    178     thiz->mState.count = 0;
    179     thiz->mState.playIndex = 0;
    180     thiz->mCallback = NULL;
    181     thiz->mContext = NULL;
    182     thiz->mNumBuffers = 0;
    183     thiz->mClearRequested = SL_BOOLEAN_FALSE;
    184     thiz->mArray = NULL;
    185     thiz->mFront = NULL;
    186     thiz->mRear = NULL;
    187 #ifdef ANDROID
    188     thiz->mSizeConsumed = 0;
    189     thiz->mCallbackPending = false;
    190 #endif
    191     BufferHeader *bufferHeader = thiz->mTypical;
    192     unsigned i;
    193     for (i = 0; i < BUFFER_HEADER_TYPICAL+1; ++i, ++bufferHeader) {
    194         bufferHeader->mBuffer = NULL;
    195         bufferHeader->mSize = 0;
    196     }
    197 }
    198 
    199 
    200 /** \brief Interface deinitialization hook called by IObject::Destroy.
    201  *  Free the buffer queue, if it was larger than typical.
    202  */
    203 
    204 void IBufferQueue_deinit(void *self)
    205 {
    206     IBufferQueue *thiz = (IBufferQueue *) self;
    207     if ((NULL != thiz->mArray) && (thiz->mArray != thiz->mTypical)) {
    208         free(thiz->mArray);
    209         thiz->mArray = NULL;
    210     }
    211 }
    212