OSDN Git Service

aaudio: fix intermittent hang and position error
authorPhil Burk <philburk@google.com>
Tue, 18 Jul 2017 00:00:02 +0000 (17:00 -0700)
committerPhil Burk <philburk@google.com>
Tue, 18 Jul 2017 00:00:02 +0000 (17:00 -0700)
Fix hang caused by recursive mutex.
Fix disconnect caused by getPosition() failing, which was
just because the stream wasn't ready yet.

Bug: 63775537
Bug: 63709749
Test: run "aaudio_loopback -pl -Pl -c2 -n6 -te -m" many times
Change-Id: Ic1d54360b55cfc8ecc1809584c262bc0976c58bb

media/libaaudio/src/utility/AAudioUtilities.cpp
services/oboeservice/AAudioServiceEndpoint.cpp
services/oboeservice/AAudioServiceEndpoint.h
services/oboeservice/AAudioServiceStreamBase.cpp
services/oboeservice/AAudioServiceStreamBase.h
services/oboeservice/AAudioServiceStreamMMAP.cpp

index 2d8ac6e..a3198d7 100644 (file)
@@ -229,10 +229,13 @@ status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
     case AAUDIO_ERROR_NULL:
         status = UNEXPECTED_NULL;
         break;
+    case AAUDIO_ERROR_UNAVAILABLE:
+        status = NOT_ENOUGH_DATA;
+        break;
+
     // TODO translate these result codes
     case AAUDIO_ERROR_INTERNAL:
     case AAUDIO_ERROR_UNIMPLEMENTED:
-    case AAUDIO_ERROR_UNAVAILABLE:
     case AAUDIO_ERROR_NO_FREE_HANDLES:
     case AAUDIO_ERROR_NO_MEMORY:
     case AAUDIO_ERROR_TIMEOUT:
@@ -268,6 +271,9 @@ aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) {
     case WOULD_BLOCK:
         result = AAUDIO_ERROR_WOULD_BLOCK;
         break;
+    case NOT_ENOUGH_DATA:
+        result = AAUDIO_ERROR_UNAVAILABLE;
+        break;
     default:
         result = AAUDIO_ERROR_INTERNAL;
         break;
index 5895974..1421468 100644 (file)
@@ -112,10 +112,10 @@ aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamSh
 }
 
 aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
-    // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
     aaudio_result_t result = AAUDIO_OK;
-    std::lock_guard<std::mutex> lock(mLockStreams);
     if (++mRunningStreams == 1) {
+        // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
+        std::lock_guard<std::mutex> lock(mLockStreams);
         result = getStreamInternal()->requestStart();
         startSharingThread_l();
     }
@@ -123,13 +123,8 @@ aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared>
 }
 
 aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
-    int numRunningStreams = 0;
-    {
-        std::lock_guard<std::mutex> lock(mLockStreams);
-        numRunningStreams = --mRunningStreams;
-    }
-    if (numRunningStreams == 0) {
-        // Don't call this under a lock because the callbackLoop also uses the lock.
+    // Don't lock here because the disconnectRegisteredStreams also uses the lock.
+    if (--mRunningStreams == 0) { // atomic
         stopSharingThread();
         getStreamInternal()->requestStop();
     }
index ed995e5..e40a670 100644 (file)
@@ -73,13 +73,13 @@ public:
 
     virtual AudioStreamInternal *getStreamInternal() = 0;
 
-    std::atomic<bool>        mCallbackEnabled;
+    std::atomic<bool>        mCallbackEnabled{false};
 
     mutable std::mutex       mLockStreams;
 
     std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
 
-    size_t                   mRunningStreams = 0;
+    std::atomic<int>         mRunningStreams{0};
 
 private:
     aaudio_result_t startSharingThread_l();
index e0f6ad4..5f7d179 100644 (file)
@@ -219,6 +219,8 @@ aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
     //          (long long) command.timestamp.timestamp);
         command.what = AAudioServiceMessage::code::TIMESTAMP;
         result = writeUpMessageQueue(&command);
+    } else if (result == AAUDIO_ERROR_UNAVAILABLE) {
+        result = AAUDIO_OK; // just not available yet, try again later
     }
     return result;
 }
index 93a522e..cebefec 100644 (file)
@@ -163,6 +163,11 @@ protected:
 
     aaudio_result_t sendCurrentTimestamp();
 
+    /**
+     * @param positionFrames
+     * @param timeNanos
+     * @return AAUDIO_OK or AAUDIO_ERROR_UNAVAILABLE or other negative error
+     */
     virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
     virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0;
index 68be3c3..69dbea8 100644 (file)
@@ -297,16 +297,18 @@ aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positio
         return AAUDIO_ERROR_NULL;
     }
     status_t status = mMmapStream->getMmapPosition(&position);
-    if (status != OK) {
-        ALOGE("sendCurrentTimestamp(): getMmapPosition() returned %d", status);
+    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+    if (result == AAUDIO_ERROR_UNAVAILABLE) {
+        ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data yet");
+    } else if (result != AAUDIO_OK) {
+        ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status);
         disconnect();
-        return AAudioConvert_androidToAAudioResult(status);
     } else {
         mFramesRead.update32(position.position_frames);
         *positionFrames = mFramesRead.get();
         *timeNanos = position.time_nanoseconds;
     }
-    return AAUDIO_OK;
+    return result;
 }
 
 void AAudioServiceStreamMMAP::onTearDown() {