X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=wilhelm%2Fsrc%2Fandroid%2FAudioPlayer_to_android.cpp;h=005f59f6ba901ec606b850461534bac16f3d5bd4;hb=9e0e6e5c60320dac9aa2abbce2f9a843b8fc4449;hp=5732650565e81c1ee743b3e0357f13eea9136efc;hpb=30ede43f5dab7ad0c8db91eb1976604e7d6074cb;p=android-x86%2Fsystem-media.git diff --git a/wilhelm/src/android/AudioPlayer_to_android.cpp b/wilhelm/src/android/AudioPlayer_to_android.cpp index 57326505..005f59f6 100644 --- a/wilhelm/src/android/AudioPlayer_to_android.cpp +++ b/wilhelm/src/android/AudioPlayer_to_android.cpp @@ -23,6 +23,132 @@ template class android::KeyedVector ; #define KEY_STREAM_TYPE_PARAMSIZE sizeof(SLint32) //----------------------------------------------------------------------------- +// FIXME this method will be absorbed into android_audioPlayer_setPlayState() once +// bufferqueue and uri/fd playback are moved under the GenericPlayer C++ object +SLresult aplayer_setPlayState(const android::sp &ap, SLuint32 playState, + AndroidObject_state* pObjState) { + SLresult result = SL_RESULT_SUCCESS; + AndroidObject_state objState = *pObjState; + + switch (playState) { + case SL_PLAYSTATE_STOPPED: + SL_LOGV("setting GenericPlayer to SL_PLAYSTATE_STOPPED"); + ap->stop(); + break; + case SL_PLAYSTATE_PAUSED: + SL_LOGV("setting GenericPlayer to SL_PLAYSTATE_PAUSED"); + switch(objState) { + case ANDROID_UNINITIALIZED: + *pObjState = ANDROID_PREPARING; + ap->prepare(); + break; + case ANDROID_PREPARING: + break; + case ANDROID_READY: + ap->pause(); + break; + default: + SL_LOGE(ERROR_PLAYERSETPLAYSTATE_INVALID_OBJECT_STATE_D, playState); + result = SL_RESULT_INTERNAL_ERROR; + break; + } + break; + case SL_PLAYSTATE_PLAYING: { + SL_LOGV("setting GenericPlayer to SL_PLAYSTATE_PLAYING"); + switch(objState) { + case ANDROID_UNINITIALIZED: + *pObjState = ANDROID_PREPARING; + ap->prepare(); + // intended fall through + case ANDROID_PREPARING: + // intended fall through + case ANDROID_READY: + ap->play(); + break; + default: + SL_LOGE(ERROR_PLAYERSETPLAYSTATE_INVALID_OBJECT_STATE_D, playState); + result = SL_RESULT_INTERNAL_ERROR; + break; + } + } + break; + default: + // checked by caller, should not happen + SL_LOGE(ERROR_SHOULDNT_BE_HERE_S, "aplayer_setPlayState"); + result = SL_RESULT_INTERNAL_ERROR; + break; + } + + return result; +} + + +//----------------------------------------------------------------------------- +// Callback associated with a AudioToCbRenderer of an SL ES AudioPlayer that gets its data +// from a URI or FD, to write the decoded audio data to a buffer queue +static size_t adecoder_writeToBufferQueue(const uint8_t *data, size_t size, void* user) { + size_t sizeConsumed = 0; + if (NULL == user) { + return sizeConsumed; + } + SL_LOGD("received %d bytes from decoder", size); + CAudioPlayer *ap = (CAudioPlayer *)user; + slBufferQueueCallback callback = NULL; + void * callbackPContext = NULL; + + // push decoded data to the buffer queue + object_lock_exclusive(&ap->mObject); + + if (ap->mBufferQueue.mState.count != 0) { + assert(ap->mBufferQueue.mFront != ap->mBufferQueue.mRear); + + BufferHeader *oldFront = ap->mBufferQueue.mFront; + BufferHeader *newFront = &oldFront[1]; + + uint8_t *pDest = (uint8_t *)oldFront->mBuffer + ap->mBufferQueue.mSizeConsumed; + if (ap->mBufferQueue.mSizeConsumed + size < oldFront->mSize) { + // room to consume the whole or rest of the decoded data in one shot + ap->mBufferQueue.mSizeConsumed += size; + // consume data but no callback to the BufferQueue interface here + memcpy (pDest, data, size); + sizeConsumed = size; + } else { + // push as much as possible of the decoded data into the buffer queue + sizeConsumed = oldFront->mSize - ap->mBufferQueue.mSizeConsumed; + + // the buffer at the head of the buffer queue is full, update the state + ap->mBufferQueue.mSizeConsumed = 0; + if (newFront == &ap->mBufferQueue.mArray[ap->mBufferQueue.mNumBuffers + 1]) { + newFront = ap->mBufferQueue.mArray; + } + ap->mBufferQueue.mFront = newFront; + + ap->mBufferQueue.mState.count--; + ap->mBufferQueue.mState.playIndex++; + // consume data + memcpy (pDest, data, sizeConsumed); + // data has been copied to the buffer, and the buffer queue state has been updated + // we will notify the client if applicable + callback = ap->mBufferQueue.mCallback; + // save callback data + callbackPContext = ap->mBufferQueue.mContext; + } + + } else { + // no available buffers in the queue to write the decoded data + sizeConsumed = 0; + } + + object_unlock_exclusive(&ap->mObject); + // notify client + if (NULL != callback) { + (*callback)(&ap->mBufferQueue.mItf, callbackPContext); + } + + return sizeConsumed; +} + +//----------------------------------------------------------------------------- int android_getMinFrameCount(uint32_t sampleRate) { int afSampleRate; if (android::AudioSystem::getOutputSamplingRate(&afSampleRate, @@ -375,6 +501,130 @@ void audioPlayer_auxEffectUpdate(CAudioPlayer* ap) { //----------------------------------------------------------------------------- +void audioPlayer_setInvalid(CAudioPlayer* ap) { + ap->mAndroidObjType = INVALID_TYPE; + ap->mpLock = NULL; + ap->mPlaybackRate.mCapabilities = 0; +} + + +//----------------------------------------------------------------------------- +/* + * returns true if the given data sink is supported by AudioPlayer that don't + * play to an OutputMix object, false otherwise + * + * pre-condition: the locator of the audio sink is not SL_DATALOCATOR_OUTPUTMIX + */ +bool audioPlayer_isSupportedNonOutputMixSink(const SLDataSink* pAudioSink) { + bool result = true; + const SLuint32 sinkLocatorType = *(SLuint32 *)pAudioSink->pLocator; + const SLuint32 sinkFormatType = *(SLuint32 *)pAudioSink->pFormat; + + switch (sinkLocatorType) { + + case SL_DATALOCATOR_BUFFERQUEUE: + case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: + if (SL_DATAFORMAT_PCM != sinkFormatType) { + SL_LOGE("Unsupported sink format 0x%x, expected SL_DATAFORMAT_PCM", + (unsigned)sinkFormatType); + result = false; + } + // it's no use checking the PCM format fields because additional characteristics + // such as the number of channels, or sample size are unknown to the player at this stage + break; + + default: + SL_LOGE("Unsupported sink locator type 0x%x", (unsigned)sinkLocatorType); + result = false; + break; + } + + return result; +} + + +//----------------------------------------------------------------------------- +/* + * returns the Android object type if the locator type combinations for the source and sinks + * are supported by this implementation, INVALID_TYPE otherwise + */ +AndroidObject_type audioPlayer_getAndroidObjectTypeForSourceSink(CAudioPlayer *ap) { + + const SLDataSource *pAudioSrc = &ap->mDataSource.u.mSource; + const SLDataSink *pAudioSnk = &ap->mDataSink.u.mSink; + const SLuint32 sourceLocatorType = *(SLuint32 *)pAudioSrc->pLocator; + const SLuint32 sinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator; + AndroidObject_type type = INVALID_TYPE; + + //-------------------------------------- + // Sink / source matching check: + // the following source / sink combinations are supported + // SL_DATALOCATOR_BUFFERQUEUE / SL_DATALOCATOR_OUTPUTMIX + // SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE / SL_DATALOCATOR_OUTPUTMIX + // SL_DATALOCATOR_URI / SL_DATALOCATOR_OUTPUTMIX + // SL_DATALOCATOR_ANDROIDFD / SL_DATALOCATOR_OUTPUTMIX + // SL_DATALOCATOR_ANDROIDBUFFERQUEUE / SL_DATALOCATOR_OUTPUTMIX + // SL_DATALOCATOR_URI / SL_DATALOCATOR_BUFFERQUEUE + // SL_DATALOCATOR_ANDROIDFD / SL_DATALOCATOR_BUFFERQUEUE + // SL_DATALOCATOR_URI / SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE + // SL_DATALOCATOR_ANDROIDFD / SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE + switch (sinkLocatorType) { + + case SL_DATALOCATOR_OUTPUTMIX: { + switch (sourceLocatorType) { + + // Buffer Queue to AudioTrack + case SL_DATALOCATOR_BUFFERQUEUE: + case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: + type = A_PLR_PCM_BQ; + break; + + // URI or FD to MediaPlayer + case SL_DATALOCATOR_URI: + case SL_DATALOCATOR_ANDROIDFD: + type = A_PLR_URIFD; + break; + + // Android BufferQueue to MediaPlayer (shared memory streaming) + case SL_DATALOCATOR_ANDROIDBUFFERQUEUE: + type = A_PLR_TS_ABQ; + break; + + default: + SL_LOGE("Source data locator 0x%x not supported with SL_DATALOCATOR_OUTPUTMIX sink", + (unsigned)sourceLocatorType); + break; + } + } + break; + + case SL_DATALOCATOR_BUFFERQUEUE: + case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: + switch (sourceLocatorType) { + + // URI or FD decoded to PCM in a buffer queue + case SL_DATALOCATOR_URI: + case SL_DATALOCATOR_ANDROIDFD: + type = A_PLR_URIFD_ASQ; + break; + + default: + SL_LOGE("Source data locator 0x%x not supported with SL_DATALOCATOR_BUFFERQUEUE sink", + (unsigned)sourceLocatorType); + break; + } + break; + + default: + SL_LOGE("Sink data locator 0x%x not supported", (unsigned)sinkLocatorType); + break; + } + + return type; +} + + +//----------------------------------------------------------------------------- static void sfplayer_prepare(CAudioPlayer *ap, bool lockAP) { if (lockAP) { object_lock_exclusive(&ap->mObject); } @@ -389,7 +639,7 @@ static void sfplayer_prepare(CAudioPlayer *ap, bool lockAP) { //----------------------------------------------------------------------------- // Callback associated with an SfPlayer of an SL ES AudioPlayer that gets its data // from a URI or FD, for prepare and prefetch events -static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* user) { +static void sfplayer_handlePrefetchEvent(int event, int data1, int data2, void* user) { if (NULL == user) { return; } @@ -398,7 +648,7 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* //SL_LOGV("received event %d, data %d from SfAudioPlayer", event, data1); switch(event) { - case(android::AVPlayer::kEventPrepared): { + case android::GenericPlayer::kEventPrepared: { if (PLAYER_SUCCESS != data1) { object_lock_exclusive(&ap->mObject); @@ -453,8 +703,10 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* android_audioPlayer_useEventMask(ap); android_audioPlayer_volumeUpdate(ap); android_audioPlayer_setPlayRate(ap, ap->mPlaybackRate.mRate, false /*lockAP*/); - } else if (A_PLR_TS_ABQ) { - SL_LOGI("Received SfPlayer::kEventPrepared from AVPlayer for CAudioPlayer %p", ap); + } else if (A_PLR_PCM_BQ == ap->mAndroidObjType) { + ((android::AudioToCbRenderer*)ap->mAPlayer.get())->startPrefetch_async(); + } else if (A_PLR_TS_ABQ == ap->mAndroidObjType) { + SL_LOGD("Received SfPlayer::kEventPrepared from AVPlayer for CAudioPlayer %p", ap); } ap->mAndroidObjState = ANDROID_READY; @@ -462,9 +714,10 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* object_unlock_exclusive(&ap->mObject); } - } break; + } + break; - case(android::SfPlayer::kEventNewAudioTrack): { + case android::SfPlayer::kEventNewAudioTrack: { object_lock_exclusive(&ap->mObject); #if 1 // SfPlayer has a new AudioTrack, update our pointer copy and configure the new one before @@ -489,9 +742,10 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* android_audioPlayer_setPlayRate(ap, ap->mPlaybackRate.mRate, false /*lockAP*/); object_unlock_exclusive(&ap->mObject); - } break; + } + break; - case(android::SfPlayer::kEventPrefetchFillLevelUpdate): { + case android::SfPlayer::kEventPrefetchFillLevelUpdate : { if (!IsInterfaceInitialized(&(ap->mObject), MPH_PREFETCHSTATUS)) { break; } @@ -512,9 +766,10 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* (*callback)(&ap->mPrefetchStatus.mItf, callbackPContext, SL_PREFETCHEVENT_FILLLEVELCHANGE); } - } break; + } + break; - case(android::SfPlayer::kEventPrefetchStatusChange): { + case android::SfPlayer::kEventPrefetchStatusChange: { if (!IsInterfaceInitialized(&(ap->mObject), MPH_PREFETCHSTATUS)) { break; } @@ -543,14 +798,16 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* if (NULL != callback) { (*callback)(&ap->mPrefetchStatus.mItf, callbackPContext, SL_PREFETCHEVENT_STATUSCHANGE); } - } break; + } + break; - case(android::SfPlayer::kEventEndOfStream): { + case android::SfPlayer::kEventEndOfStream: { audioPlayer_dispatch_headAtEnd_lockPlay(ap, true /*set state to paused?*/, true); if ((NULL != ap->mAudioTrack) && (!ap->mSeek.mLoopEnabled)) { ap->mAudioTrack->stop(); } - } break; + } + break; default: break; @@ -561,22 +818,22 @@ static void sfplayer_handlePrefetchEvent(const int event, const int data1, void* //----------------------------------------------------------------------------- SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) { - const SLDataSource *pAudioSrc = &pAudioPlayer->mDataSource.u.mSource; - const SLDataSink *pAudioSnk = &pAudioPlayer->mDataSink.u.mSink; - //-------------------------------------- - // Sink check: - // currently only OutputMix sinks are supported, regardless of the data source - if (*(SLuint32 *)pAudioSnk->pLocator != SL_DATALOCATOR_OUTPUTMIX) { - SL_LOGE("Cannot create audio player: data sink is not SL_DATALOCATOR_OUTPUTMIX"); + // verify that the locator types for the source / sink combination is supported + pAudioPlayer->mAndroidObjType = audioPlayer_getAndroidObjectTypeForSourceSink(pAudioPlayer); + if (INVALID_TYPE == pAudioPlayer->mAndroidObjType) { return SL_RESULT_PARAMETER_INVALID; } - //-------------------------------------- - // Source check: - SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator; - SLuint32 formatType = *(SLuint32 *)pAudioSrc->pFormat; + const SLDataSource *pAudioSrc = &pAudioPlayer->mDataSource.u.mSource; + const SLDataSink *pAudioSnk = &pAudioPlayer->mDataSink.u.mSink; + + // format check: + const SLuint32 sourceLocatorType = *(SLuint32 *)pAudioSrc->pLocator; + const SLuint32 sinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator; + const SLuint32 sourceFormatType = *(SLuint32 *)pAudioSrc->pFormat; + const SLuint32 sinkFormatType = *(SLuint32 *)pAudioSnk->pFormat; - switch (locatorType) { + switch (sourceLocatorType) { //------------------ // Buffer Queues case SL_DATALOCATOR_BUFFERQUEUE: @@ -585,7 +842,7 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) SLDataLocator_BufferQueue *dl_bq = (SLDataLocator_BufferQueue *) pAudioSrc->pLocator; // Buffer format - switch (formatType) { + switch (sourceFormatType) { // currently only PCM buffer queues are supported, case SL_DATAFORMAT_PCM: { SLDataFormat_PCM *df_pcm = (SLDataFormat_PCM *) pAudioSrc->pFormat; @@ -671,7 +928,7 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) // invalid data format is detected earlier assert(false); return SL_RESULT_INTERNAL_ERROR; - } // switch (formatType) + } // switch (sourceFormatType) } // case SL_DATALOCATOR_BUFFERQUEUE or SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE break; //------------------ @@ -683,7 +940,7 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) return SL_RESULT_PARAMETER_INVALID; } // URI format - switch (formatType) { + switch (sourceFormatType) { case SL_DATAFORMAT_MIME: break; case SL_DATAFORMAT_PCM: @@ -691,7 +948,12 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) SL_LOGE("Cannot create audio player with SL_DATALOCATOR_URI data source without " "SL_DATAFORMAT_MIME format"); return SL_RESULT_CONTENT_UNSUPPORTED; - } // switch (formatType) + } // switch (sourceFormatType) + // decoding format check + if ((sinkLocatorType != SL_DATALOCATOR_OUTPUTMIX) && + !audioPlayer_isSupportedNonOutputMixSink(pAudioSnk)) { + return SL_RESULT_CONTENT_UNSUPPORTED; + } } // case SL_DATALOCATOR_URI break; //------------------ @@ -699,7 +961,7 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) case SL_DATALOCATOR_ANDROIDFD: { // fd is already non null - switch (formatType) { + switch (sourceFormatType) { case SL_DATAFORMAT_MIME: break; case SL_DATAFORMAT_PCM: @@ -714,15 +976,35 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) // invalid data format is detected earlier assert(false); return SL_RESULT_INTERNAL_ERROR; - } // switch (formatType) + } // switch (sourceFormatType) + if ((sinkLocatorType != SL_DATALOCATOR_OUTPUTMIX) && + !audioPlayer_isSupportedNonOutputMixSink(pAudioSnk)) { + return SL_RESULT_CONTENT_UNSUPPORTED; + } } // case SL_DATALOCATOR_ANDROIDFD break; //------------------ // Stream case SL_DATALOCATOR_ANDROIDBUFFERQUEUE: + { + switch (sourceFormatType) { + case SL_DATAFORMAT_MIME: { - } // case SL_DATALOCATOR_ANDROIDBUFFERQUEUE + SLDataFormat_MIME *df_mime = (SLDataFormat_MIME *) pAudioSrc->pFormat; + if (SL_CONTAINERTYPE_MPEG_TS != df_mime->containerType) { + SL_LOGE("Cannot create player with SL_DATALOCATOR_ANDROIDBUFFERQUEUE data source " + "that is not fed MPEG-2 TS data"); + return SL_RESULT_CONTENT_UNSUPPORTED; + } + } break; + default: + SL_LOGE("Cannot create player with SL_DATALOCATOR_ANDROIDBUFFERQUEUE data source " + "without SL_DATAFORMAT_MIME format"); + return SL_RESULT_CONTENT_UNSUPPORTED; + } + } + break; // case SL_DATALOCATOR_ANDROIDBUFFERQUEUE //------------------ // Address case SL_DATALOCATOR_ADDRESS: @@ -730,11 +1012,12 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) case SL_DATALOCATOR_OUTPUTMIX: case XA_DATALOCATOR_NATIVEDISPLAY: case SL_DATALOCATOR_MIDIBUFFERQUEUE: - SL_LOGE("Cannot create audio player with data locator type 0x%x", (unsigned) locatorType); + SL_LOGE("Cannot create audio player with data locator type 0x%x", + (unsigned) sourceLocatorType); return SL_RESULT_CONTENT_UNSUPPORTED; default: SL_LOGE("Cannot create audio player with invalid data locator type 0x%x", - (unsigned) locatorType); + (unsigned) sourceLocatorType); return SL_RESULT_PARAMETER_INVALID; }// switch (locatorType) @@ -747,47 +1030,62 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer) static void audioTrack_callBack_uri(int event, void* user, void *info) { // EVENT_MORE_DATA needs to be handled with priority over the other events // because it will be called the most often during playback + if (event == android::AudioTrack::EVENT_MORE_DATA) { //SL_LOGV("received event EVENT_MORE_DATA from AudioTrack"); // set size to 0 to signal we're not using the callback to write more data android::AudioTrack::Buffer* pBuff = (android::AudioTrack::Buffer*)info; pBuff->size = 0; } else if (NULL != user) { + CAudioPlayer *ap = (CAudioPlayer *)user; + if (!ap->mAudioTrackProtector->enterCb()) { + // it is not safe to enter the callback (the track is about to go away) + return; + } switch (event) { - case (android::AudioTrack::EVENT_MARKER) : - audioTrack_handleMarker_lockPlay((CAudioPlayer *)user); + case android::AudioTrack::EVENT_MARKER : + audioTrack_handleMarker_lockPlay(ap); break; - case (android::AudioTrack::EVENT_NEW_POS) : - audioTrack_handleNewPos_lockPlay((CAudioPlayer *)user); + case android::AudioTrack::EVENT_NEW_POS : + audioTrack_handleNewPos_lockPlay(ap); break; - case (android::AudioTrack::EVENT_UNDERRUN) : - audioTrack_handleUnderrun_lockPlay((CAudioPlayer *)user); + case android::AudioTrack::EVENT_UNDERRUN : + audioTrack_handleUnderrun_lockPlay(ap); break; - case (android::AudioTrack::EVENT_BUFFER_END) : - case (android::AudioTrack::EVENT_LOOP_END) : + case android::AudioTrack::EVENT_BUFFER_END : + case android::AudioTrack::EVENT_LOOP_END : break; default: SL_LOGE("Encountered unknown AudioTrack event %d for CAudioPlayer %p", event, - (CAudioPlayer *)user); + ap); break; } + ap->mAudioTrackProtector->exitCb(); } } //----------------------------------------------------------------------------- // Callback associated with an AudioTrack of an SL ES AudioPlayer that gets its data -// from a buffer queue. +// from a buffer queue. This will not be called once the AudioTrack has been destroyed. static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *info) { CAudioPlayer *ap = (CAudioPlayer *)user; + + if (!ap->mAudioTrackProtector->enterCb()) { + // it is not safe to enter the callback (the track is about to go away) + return; + } + void * callbackPContext = NULL; switch(event) { - case (android::AudioTrack::EVENT_MORE_DATA) : { - //SL_LOGV("received event EVENT_MORE_DATA from AudioTrack"); + case android::AudioTrack::EVENT_MORE_DATA: { + //SL_LOGV("received event EVENT_MORE_DATA from AudioTrack TID=%d", gettid()); slBufferQueueCallback callback = NULL; android::AudioTrack::Buffer* pBuff = (android::AudioTrack::Buffer*)info; + // retrieve data from the buffer queue interface_lock_exclusive(&ap->mBufferQueue); + if (ap->mBufferQueue.mState.count != 0) { //SL_LOGV("nbBuffers in queue = %lu",ap->mBufferQueue.mState.count); assert(ap->mBufferQueue.mFront != ap->mBufferQueue.mRear); @@ -848,6 +1146,7 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i ap->mAudioTrack->stop(); } interface_unlock_exclusive(&ap->mBufferQueue); + // notify client if (NULL != callback) { (*callback)(&ap->mBufferQueue.mItf, callbackPContext); @@ -855,15 +1154,18 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i } break; - case (android::AudioTrack::EVENT_MARKER) : + case android::AudioTrack::EVENT_MARKER: + //SL_LOGI("received event EVENT_MARKER from AudioTrack"); audioTrack_handleMarker_lockPlay(ap); break; - case (android::AudioTrack::EVENT_NEW_POS) : + case android::AudioTrack::EVENT_NEW_POS: + //SL_LOGI("received event EVENT_NEW_POS from AudioTrack"); audioTrack_handleNewPos_lockPlay(ap); break; - case (android::AudioTrack::EVENT_UNDERRUN) : + case android::AudioTrack::EVENT_UNDERRUN: + //SL_LOGI("received event EVENT_UNDERRUN from AudioTrack"); audioTrack_handleUnderrun_lockPlay(ap); break; @@ -873,79 +1175,45 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i (CAudioPlayer *)user); break; } + + ap->mAudioTrackProtector->exitCb(); } //----------------------------------------------------------------------------- -SLresult android_audioPlayer_create( - CAudioPlayer *pAudioPlayer) { +SLresult android_audioPlayer_create(CAudioPlayer *pAudioPlayer) { - const SLDataSource *pAudioSrc = &pAudioPlayer->mDataSource.u.mSource; - const SLDataSink *pAudioSnk = &pAudioPlayer->mDataSink.u.mSink; SLresult result = SL_RESULT_SUCCESS; + // pAudioPlayer->mAndroidObjType has been set in audioPlayer_getAndroidObjectTypeForSourceSink() + if (INVALID_TYPE == pAudioPlayer->mAndroidObjType) { + audioPlayer_setInvalid(pAudioPlayer); + result = SL_RESULT_PARAMETER_INVALID; + } else { - //-------------------------------------- - // Sink check: - // currently only OutputMix sinks are supported - // this has already been verified in sles_to_android_CheckAudioPlayerSourceSink - // SLuint32 locatorType = *(SLuint32 *)pAudioSnk->pLocator; - // if (SL_DATALOCATOR_OUTPUTMIX == locatorType) { - // } - - //-------------------------------------- - // Source check: - SLuint32 locatorType = *(SLuint32 *)pAudioSrc->pLocator; - switch (locatorType) { - // ----------------------------------- - // Buffer Queue to AudioTrack - case SL_DATALOCATOR_BUFFERQUEUE: - case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: - pAudioPlayer->mAndroidObjType = A_PLR_PCM_BQ; pAudioPlayer->mpLock = new android::Mutex(); - pAudioPlayer->mPlaybackRate.mCapabilities = SL_RATEPROP_NOPITCHCORAUDIO; - break; - // ----------------------------------- - // URI or FD to MediaPlayer - case SL_DATALOCATOR_URI: - case SL_DATALOCATOR_ANDROIDFD: - pAudioPlayer->mAndroidObjType = A_PLR_URIFD; - pAudioPlayer->mpLock = new android::Mutex(); - pAudioPlayer->mPlaybackRate.mCapabilities = SL_RATEPROP_NOPITCHCORAUDIO; - break; - case SL_DATALOCATOR_ANDROIDBUFFERQUEUE: - pAudioPlayer->mAndroidObjType = A_PLR_TS_ABQ; - pAudioPlayer->mpLock = new android::Mutex(); - pAudioPlayer->mPlaybackRate.mCapabilities = SL_RATEPROP_NOPITCHCORAUDIO; - break; - default: - pAudioPlayer->mAndroidObjType = INVALID_TYPE; - pAudioPlayer->mpLock = NULL; - pAudioPlayer->mPlaybackRate.mCapabilities = 0; - result = SL_RESULT_PARAMETER_INVALID; - break; - } + pAudioPlayer->mAndroidObjState = ANDROID_UNINITIALIZED; + pAudioPlayer->mStreamType = ANDROID_DEFAULT_OUTPUT_STREAM_TYPE; + pAudioPlayer->mAudioTrack = NULL; + // not needed, as placement new (explicit constructor) already does this + // pAudioPlayer->mSfPlayer.clear(); - pAudioPlayer->mAndroidObjState = ANDROID_UNINITIALIZED; - pAudioPlayer->mStreamType = ANDROID_DEFAULT_OUTPUT_STREAM_TYPE; - pAudioPlayer->mAudioTrack = NULL; - // no longer needed, as placement new (explicit constructor) already does this - // pAudioPlayer->mSfPlayer.clear(); + pAudioPlayer->mAudioTrackProtector = new android::AudioTrackProtector(); - pAudioPlayer->mSessionId = android::AudioSystem::newAudioSessionId(); + pAudioPlayer->mSessionId = android::AudioSystem::newAudioSessionId(); - pAudioPlayer->mAmplFromVolLevel = 1.0f; - pAudioPlayer->mAmplFromStereoPos[0] = 1.0f; - pAudioPlayer->mAmplFromStereoPos[1] = 1.0f; - pAudioPlayer->mDirectLevel = 0; // no attenuation - pAudioPlayer->mAmplFromDirectLevel = 1.0f; // matches initial mDirectLevel value - pAudioPlayer->mAuxSendLevel = 0; + pAudioPlayer->mAmplFromVolLevel = 1.0f; + pAudioPlayer->mAmplFromStereoPos[0] = 1.0f; + pAudioPlayer->mAmplFromStereoPos[1] = 1.0f; + pAudioPlayer->mDirectLevel = 0; // no attenuation + pAudioPlayer->mAmplFromDirectLevel = 1.0f; // matches initial mDirectLevel value + pAudioPlayer->mAuxSendLevel = 0; - // initialize interface-specific fields that can be used regardless of whether the interface - // is exposed on the AudioPlayer or not - // (section no longer applicable, as all previous initializations were the same as the defaults) + // initialize interface-specific fields that can be used regardless of whether the + // interface is exposed on the AudioPlayer or not + // (empty section, as all initializations are the same as the defaults) + } return result; - } @@ -1059,7 +1327,8 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async pAudioPlayer->mSampleRateMilliHz = df_pcm->samplesPerSec; // Note: bad field name in SL ES pAudioPlayer->mAndroidObjState = ANDROID_READY; - } break; + } + break; //----------------------------------- // MediaPlayer case A_PLR_URIFD: { @@ -1095,26 +1364,65 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async offset == SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE ? (int64_t)PLAYER_FD_FIND_FILE_SIZE : offset, (int64_t)pAudioPlayer->mDataSource.mLocator.mFD.length); - } break; + } + break; default: SL_LOGE(ERROR_PLAYERREALIZE_UNKNOWN_DATASOURCE_LOCATOR); break; } - } break; - //----------------------------------- - // StreamPlayer - case A_PLR_TS_ABQ: { + } + break; + //----------------------------------- + // StreamPlayer + case A_PLR_TS_ABQ: { object_lock_exclusive(&pAudioPlayer->mObject); android_StreamPlayer_realize_l(pAudioPlayer, sfplayer_handlePrefetchEvent, (void*)pAudioPlayer); object_unlock_exclusive(&pAudioPlayer->mObject); - } break; + } + break; + //----------------------------------- + // AudioToCbRenderer + case A_PLR_URIFD_ASQ: { + object_lock_exclusive(&pAudioPlayer->mObject); + + AudioPlayback_Parameters app; + app.sessionId = pAudioPlayer->mSessionId; + app.streamType = pAudioPlayer->mStreamType; + + android::AudioToCbRenderer* decoder = new android::AudioToCbRenderer(&app); + pAudioPlayer->mAPlayer = decoder; + decoder->setDataPushListener(adecoder_writeToBufferQueue, (void*)pAudioPlayer); + decoder->init(sfplayer_handlePrefetchEvent, (void*)pAudioPlayer); + + switch (pAudioPlayer->mDataSource.mLocator.mLocatorType) { + case SL_DATALOCATOR_URI: + decoder->setDataSource( + (const char*)pAudioPlayer->mDataSource.mLocator.mURI.URI); + break; + case SL_DATALOCATOR_ANDROIDFD: { + int64_t offset = (int64_t)pAudioPlayer->mDataSource.mLocator.mFD.offset; + decoder->setDataSource( + (int)pAudioPlayer->mDataSource.mLocator.mFD.fd, + offset == SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE ? + (int64_t)PLAYER_FD_FIND_FILE_SIZE : offset, + (int64_t)pAudioPlayer->mDataSource.mLocator.mFD.length); + } + break; + default: + SL_LOGE(ERROR_PLAYERREALIZE_UNKNOWN_DATASOURCE_LOCATOR); + break; + } + + object_unlock_exclusive(&pAudioPlayer->mObject); + } + break; //----------------------------------- default: - SL_LOGE("Unexpected object type %d", pAudioPlayer->mAndroidObjType); + SL_LOGE(ERROR_PLAYERREALIZE_UNEXPECTED_OBJECT_TYPE_D, pAudioPlayer->mAndroidObjType); result = SL_RESULT_INTERNAL_ERROR; break; } @@ -1149,6 +1457,23 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async //----------------------------------------------------------------------------- +/** + * Called with a lock on AudioPlayer + */ +SLresult android_audioPlayer_preDestroy(CAudioPlayer *pAudioPlayer) { + SLresult result = SL_RESULT_SUCCESS; + + object_unlock_exclusive(&pAudioPlayer->mObject); + if (pAudioPlayer->mAudioTrackProtector != 0) { + pAudioPlayer->mAudioTrackProtector->requestCbExitAndWait(); + } + object_lock_exclusive(&pAudioPlayer->mObject); + + return result; +} + + +//----------------------------------------------------------------------------- SLresult android_audioPlayer_destroy(CAudioPlayer *pAudioPlayer) { SLresult result = SL_RESULT_SUCCESS; SL_LOGV("android_audioPlayer_destroy(%p)", pAudioPlayer); @@ -1169,28 +1494,33 @@ SLresult android_audioPlayer_destroy(CAudioPlayer *pAudioPlayer) { // We don't own this audio track, SfPlayer does pAudioPlayer->mAudioTrack = NULL; // FIXME might no longer be needed since we call explicit destructor - if (pAudioPlayer->mSfPlayer != 0) { - pAudioPlayer->mSfPlayer.clear(); - } + pAudioPlayer->mSfPlayer.clear(); break; //----------------------------------- // StreamPlayer - case A_PLR_TS_ABQ: - android_StreamPlayer_destroy(pAudioPlayer); + case A_PLR_TS_ABQ: // intended fall-through + //----------------------------------- + // AudioToCbRenderer + case A_PLR_URIFD_ASQ: + pAudioPlayer->mAPlayer.clear(); break; //----------------------------------- default: - SL_LOGE("Unexpected object type %d", pAudioPlayer->mAndroidObjType); + SL_LOGE(ERROR_PLAYERDESTROY_UNEXPECTED_OBJECT_TYPE_D, pAudioPlayer->mAndroidObjType); result = SL_RESULT_INTERNAL_ERROR; break; } + pAudioPlayer->mAudioTrackProtector.clear(); + // FIXME might not be needed pAudioPlayer->mAndroidObjType = INVALID_TYPE; // explicit destructor + pAudioPlayer->mAudioTrackProtector.~sp(); pAudioPlayer->mSfPlayer.~sp(); pAudioPlayer->mAuxEffect.~sp(); + pAudioPlayer->mAPlayer.~sp(); if (pAudioPlayer->mpLock != NULL) { delete pAudioPlayer->mpLock; @@ -1308,16 +1638,17 @@ void android_audioPlayer_setPlayState(CAudioPlayer *ap, bool lockAP) { if (ap->mSfPlayer != 0) { ap->mSfPlayer->stop(); } - } break; + } + break; case SL_PLAYSTATE_PAUSED: { SL_LOGV("setting AudioPlayer to SL_PLAYSTATE_PAUSED"); switch(objState) { - case(ANDROID_UNINITIALIZED): + case ANDROID_UNINITIALIZED: sfplayer_prepare(ap, lockAP); break; - case(ANDROID_PREPARING): + case ANDROID_PREPARING: break; - case(ANDROID_READY): + case ANDROID_READY: if (ap->mSfPlayer != 0) { ap->mSfPlayer->pause(); } @@ -1325,15 +1656,16 @@ void android_audioPlayer_setPlayState(CAudioPlayer *ap, bool lockAP) { default: break; } - } break; + } + break; case SL_PLAYSTATE_PLAYING: { SL_LOGV("setting AudioPlayer to SL_PLAYSTATE_PLAYING"); switch(objState) { - case(ANDROID_UNINITIALIZED): + case ANDROID_UNINITIALIZED: sfplayer_prepare(ap, lockAP); // fall through - case(ANDROID_PREPARING): - case(ANDROID_READY): + case ANDROID_PREPARING: + case ANDROID_READY: if (ap->mSfPlayer != 0) { ap->mSfPlayer->play(); } @@ -1341,7 +1673,8 @@ void android_audioPlayer_setPlayState(CAudioPlayer *ap, bool lockAP) { default: break; } - } break; + } + break; default: // checked by caller, should not happen @@ -1349,15 +1682,14 @@ void android_audioPlayer_setPlayState(CAudioPlayer *ap, bool lockAP) { } break; - case A_PLR_TS_ABQ: { - android::AVPlayer* avp = (android::AVPlayer*) ap->mStreamPlayer.get(); - if (avp != NULL) { - android_Player_setPlayState(avp, playState, &(ap->mAndroidObjState)); - } - } + case A_PLR_TS_ABQ: // intended fall-through + case A_PLR_URIFD_ASQ: + // FIXME report and use the return code to the lock mechanism, which is where play state + // changes are updated (see object_unlock_exclusive_attributes()) + aplayer_setPlayState(ap->mAPlayer, playState, &(ap->mAndroidObjState)); break; - default: + SL_LOGE(ERROR_PLAYERSETPLAYSTATE_UNEXPECTED_OBJECT_TYPE_D, ap->mAndroidObjType); break; } } @@ -1421,10 +1753,13 @@ SLresult android_audioPlayer_getDuration(IPlay *pPlayItf, SLmillisecond *pDurMse int64_t durationUsec = SL_TIME_UNKNOWN; if (ap->mSfPlayer != 0) { durationUsec = ap->mSfPlayer->getDurationUsec(); - *pDurMsec = durationUsec == -1 ? SL_TIME_UNKNOWN : durationUsec / 1000; } - } break; + *pDurMsec = durationUsec == -1 ? SL_TIME_UNKNOWN : durationUsec / 1000; + } + break; + case A_PLR_TS_ABQ: // intended fall-through default: + *pDurMsec = SL_TIME_UNKNOWN; break; } return SL_RESULT_SUCCESS; @@ -1518,7 +1853,7 @@ SLresult android_audioPlayer_volumeUpdate(CAudioPlayer* ap) { //----------------------------------------------------------------------------- -void android_audioPlayer_bufferQueue_onRefilled(CAudioPlayer *ap) { +void android_audioPlayer_bufferQueue_onRefilled_l(CAudioPlayer *ap) { // the AudioTrack associated with the AudioPlayer receiving audio from a PCM buffer // queue was stopped when the queue become empty, we restart as soon as a new buffer // has been enqueued since we're in playing state @@ -1561,9 +1896,10 @@ SLresult android_audioPlayer_bufferQueue_onClear(CAudioPlayer *ap) { //----------------------------------------------------------------------------- void android_audioPlayer_androidBufferQueue_registerCallback_l(CAudioPlayer *ap) { - if ((ap->mAndroidObjType == A_PLR_TS_ABQ) && (ap->mStreamPlayer != 0)) { - android_StreamPlayer_androidBufferQueue_registerCallback(ap->mStreamPlayer.get(), - ap->mAndroidBufferQueue.mCallback, + if ((ap->mAndroidObjType == A_PLR_TS_ABQ) && (ap->mAPlayer != 0)) { + android::StreamPlayer* splr = static_cast(ap->mAPlayer.get()); + splr->registerQueueCallback( + (const void*)ap, true /*userIsAudioPlayer*/, ap->mAndroidBufferQueue.mContext, (const void*)&(ap->mAndroidBufferQueue.mItf)); } @@ -1571,14 +1907,15 @@ void android_audioPlayer_androidBufferQueue_registerCallback_l(CAudioPlayer *ap) //----------------------------------------------------------------------------- void android_audioPlayer_androidBufferQueue_clear_l(CAudioPlayer *ap) { - if (ap->mAndroidObjType == A_PLR_TS_ABQ) { - android_StreamPlayer_clear_l(ap); + if ((ap->mAndroidObjType == A_PLR_TS_ABQ) && (ap->mAPlayer != 0)) { + android::StreamPlayer* splr = static_cast(ap->mAPlayer.get()); + splr->appClear_l(); } } -void android_audioPlayer_androidBufferQueue_enqueue_l(CAudioPlayer *ap, - SLuint32 bufferId, SLuint32 length, SLAbufferQueueEvent event, void *pData) { - if (ap->mAndroidObjType == A_PLR_TS_ABQ) { - android_StreamPlayer_enqueue_l(ap, bufferId, length, event, pData); +void android_audioPlayer_androidBufferQueue_onRefilled_l(CAudioPlayer *ap) { + if ((ap->mAndroidObjType == A_PLR_TS_ABQ) && (ap->mAPlayer != 0)) { + android::StreamPlayer* splr = static_cast(ap->mAPlayer.get()); + splr->queueRefilled_l(); } }