OSDN Git Service

Fix bug 4109988 fix deadlock on destroy
[android-x86/system-media.git] / wilhelm / src / android / AudioPlayer_to_android.cpp
index 3084b9d..005f59f 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include "sles_allinclusive.h"
-#include "android/AndroidBufferQueueSource.h"
 #include "utils/RefBase.h"
 #include "android_prompts.h"
 
@@ -92,7 +91,7 @@ static size_t adecoder_writeToBufferQueue(const uint8_t *data, size_t size, void
     if (NULL == user) {
         return sizeConsumed;
     }
-    SL_LOGI("received %d bytes from decoder", size);
+    SL_LOGD("received %d bytes from decoder", size);
     CAudioPlayer *ap = (CAudioPlayer *)user;
     slBufferQueueCallback callback = NULL;
     void * callbackPContext = NULL;
@@ -640,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(int event, int data1, void* user) {
+static void sfplayer_handlePrefetchEvent(int event, int data1, int data2, void* user) {
     if (NULL == user) {
         return;
     }
@@ -707,7 +706,7 @@ static void sfplayer_handlePrefetchEvent(int event, int data1, void* user) {
             } else if (A_PLR_PCM_BQ == ap->mAndroidObjType) {
                 ((android::AudioToCbRenderer*)ap->mAPlayer.get())->startPrefetch_async();
             } else if (A_PLR_TS_ABQ == ap->mAndroidObjType) {
-                SL_LOGI("Received SfPlayer::kEventPrepared from AVPlayer for CAudioPlayer %p", ap);
+                SL_LOGD("Received SfPlayer::kEventPrepared from AVPlayer for CAudioPlayer %p", ap);
             }
 
             ap->mAndroidObjState = ANDROID_READY;
@@ -1031,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);
+                audioTrack_handleMarker_lockPlay(ap);
                 break;
             case android::AudioTrack::EVENT_NEW_POS :
-                audioTrack_handleNewPos_lockPlay((CAudioPlayer *)user);
+                audioTrack_handleNewPos_lockPlay(ap);
                 break;
             case android::AudioTrack::EVENT_UNDERRUN :
-                audioTrack_handleUnderrun_lockPlay((CAudioPlayer *)user);
+                audioTrack_handleUnderrun_lockPlay(ap);
                 break;
             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");
+        //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);
@@ -1132,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);
@@ -1140,14 +1155,17 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i
     break;
 
     case android::AudioTrack::EVENT_MARKER:
+        //SL_LOGI("received event EVENT_MARKER from AudioTrack");
         audioTrack_handleMarker_lockPlay(ap);
         break;
 
     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:
+        //SL_LOGI("received event EVENT_UNDERRUN from AudioTrack");
         audioTrack_handleUnderrun_lockPlay(ap);
         break;
 
@@ -1157,6 +1175,8 @@ static void audioTrack_callBack_pullFromBuffQueue(int event, void* user, void *i
                 (CAudioPlayer *)user);
         break;
     }
+
+    ap->mAudioTrackProtector->exitCb();
 }
 
 
@@ -1177,6 +1197,8 @@ SLresult android_audioPlayer_create(CAudioPlayer *pAudioPlayer) {
         // not needed, as placement new (explicit constructor) already does this
         // pAudioPlayer->mSfPlayer.clear();
 
+        pAudioPlayer->mAudioTrackProtector = new android::AudioTrackProtector();
+
         pAudioPlayer->mSessionId = android::AudioSystem::newAudioSessionId();
 
         pAudioPlayer->mAmplFromVolLevel = 1.0f;
@@ -1435,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);
@@ -1472,10 +1511,13 @@ SLresult android_audioPlayer_destroy(CAudioPlayer *pAudioPlayer) {
         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();
@@ -1604,7 +1646,7 @@ void android_audioPlayer_setPlayState(CAudioPlayer *ap, bool lockAP) {
                 case ANDROID_UNINITIALIZED:
                     sfplayer_prepare(ap, lockAP);
                     break;
-                caseANDROID_PREPARING:
+                case ANDROID_PREPARING:
                     break;
                 case ANDROID_READY:
                     if (ap->mSfPlayer != 0) {
@@ -1711,11 +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;
         }
+        *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;
@@ -1809,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
@@ -1851,13 +1895,10 @@ SLresult android_audioPlayer_bufferQueue_onClear(CAudioPlayer *ap) {
 
 
 //-----------------------------------------------------------------------------
-// abqSrc_callBack_pullFromBuffQueue is implemented in AndroidBufferQueueSource.cpp
 void android_audioPlayer_androidBufferQueue_registerCallback_l(CAudioPlayer *ap) {
     if ((ap->mAndroidObjType == A_PLR_TS_ABQ) && (ap->mAPlayer != 0)) {
         android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(ap->mAPlayer.get());
         splr->registerQueueCallback(
-                ap->mAndroidBufferQueue.mCallback,
-                abqSrc_callBack_pullFromBuffQueue,
                 (const void*)ap, true /*userIsAudioPlayer*/,
                 ap->mAndroidBufferQueue.mContext,
                 (const void*)&(ap->mAndroidBufferQueue.mItf));
@@ -1866,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<android::StreamPlayer*>(ap->mAPlayer.get());
+        splr->appClear_l();
     }
 }
 
-void android_audioPlayer_androidBufferQueue_enqueue_l(CAudioPlayer *ap,
-        SLuint32 bufferId, SLuint32 length, SLuint32 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<android::StreamPlayer*>(ap->mAPlayer.get());
+        splr->queueRefilled_l();
     }
 }