AudioTrack: fix stall if setBufferSizeInFrames() called before play()

The server was waiting for a full buffer.
But the buffer was only getting partly filled.
So the stream was not starting.

The fix involves having the server look at the adjustable threshold.

Bug: 27505889
Change-Id: I5dbf686413e670dacbbecc9e0f838744e465f44f
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ea8a78e..24784ea 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -177,6 +177,10 @@
                 // server write-only, client read
                 ExtendedTimestampQueue::Shared mExtendedTimestampQueue;
 
+                // This is set by AudioTrack.setBufferSizeInFrames().
+                // A write will not fill the buffer above this limit.
+    volatile    uint32_t   mBufferSizeInFrames;  // effective size of the buffer
+
 public:
 
     volatile    int32_t     mFlags;         // combinations of CBLK_*
@@ -312,9 +316,9 @@
         return mEpoch;
     }
 
-    size_t      getBufferSizeInFrames() const { return mBufferSizeInFrames; }
-    // See documentation for AudioTrack.setBufferSizeInFrames()
-    size_t      setBufferSizeInFrames(size_t requestedSize);
+    uint32_t      getBufferSizeInFrames() const { return mBufferSizeInFrames; }
+    // See documentation for AudioTrack::setBufferSizeInFrames()
+    uint32_t      setBufferSizeInFrames(uint32_t requestedSize);
 
     status_t    getTimestamp(ExtendedTimestamp *timestamp) {
         if (timestamp == nullptr) {
@@ -329,12 +333,10 @@
         mTimestamp.clear();
     }
 
-protected:
-    // This is set by AudioTrack.setBufferSizeInFrames().
-    // A write will not fill the buffer above this limit.
-    size_t      mBufferSizeInFrames;      // effective size of the buffer
-
 private:
+    // This is a copy of mCblk->mBufferSizeInFrames
+    uint32_t   mBufferSizeInFrames;  // effective size of the buffer
+
     Modulo<uint32_t> mEpoch;
 
     // The shared buffer contents referred to by the timestamp observer
@@ -518,6 +520,11 @@
         mTimestampMutator.push(timestamp);
     }
 
+    // Get dynamic buffer size from the shared control block.
+    uint32_t            getBufferSizeInFrames() const {
+        return android_atomic_acquire_load((int32_t *)&mCblk->mBufferSizeInFrames);
+    }
+
 protected:
     size_t      mAvailToClient; // estimated frames available to client prior to releaseBuffer()
     int32_t     mFlush;         // our copy of cblk->u.mStreaming.mFlush, for streaming output only
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 423273d..272b0cd 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -860,7 +860,7 @@
     if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
         return NO_INIT;
     }
-    return mProxy->getBufferSizeInFrames();
+    return (ssize_t) mProxy->getBufferSizeInFrames();
 }
 
 ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
@@ -873,10 +873,7 @@
     if (!audio_is_linear_pcm(mFormat)) {
         return INVALID_OPERATION;
     }
-    // TODO also need to inform the server side (through mAudioTrack) that
-    // the buffer count is reduced, otherwise the track may never start
-    // because the server thinks it is never filled.
-    return mProxy->setBufferSizeInFrames(bufferSizeInFrames);
+    return (ssize_t) mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 1d15495..7d7134a 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -46,8 +46,10 @@
 }
 
 audio_track_cblk_t::audio_track_cblk_t()
-    : mServer(0), mFutex(0), mMinimum(0),
-    mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
+    : mServer(0), mFutex(0), mMinimum(0)
+    , mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0)
+    , mBufferSizeInFrames(0)
+    , mFlags(0)
 {
     memset(&u, 0, sizeof(u));
 }
@@ -67,10 +69,10 @@
 ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
         size_t frameSize, bool isOut, bool clientInServer)
     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
-    , mBufferSizeInFrames(frameCount)
     , mEpoch(0)
     , mTimestampObserver(&cblk->mExtendedTimestampQueue)
 {
+    setBufferSizeInFrames(frameCount);
 }
 
 const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
@@ -84,6 +86,26 @@
 // order of minutes.
 #define MAX_SEC    5
 
+uint32_t ClientProxy::setBufferSizeInFrames(uint32_t size)
+{
+    // TODO set minimum to 2X the fast mixer buffer size.
+    // The minimum should be  greater than zero and less than the size
+    // at which underruns will occur.
+    const uint32_t minimum = 128 * 2; // arbitrary
+    const uint32_t maximum = frameCount();
+    uint32_t clippedSize = size;
+    if (clippedSize < minimum) {
+        clippedSize = minimum;
+    } else if (clippedSize > maximum) {
+        clippedSize = maximum;
+    }
+    // for server to read
+    android_atomic_release_store(clippedSize, (int32_t *)&mCblk->mBufferSizeInFrames);
+    // for client to read
+    mBufferSizeInFrames = clippedSize;
+    return clippedSize;
+}
+
 status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
         struct timespec *elapsed)
 {
@@ -174,7 +196,7 @@
         // The calculation for avail can go negative if the buffer size
         // is suddenly dropped below the amount already in the buffer.
         // So use a signed calculation to prevent a numeric overflow abort.
-        ssize_t adjustableSize = (ssize_t) mBufferSizeInFrames;
+        ssize_t adjustableSize = (ssize_t) getBufferSizeInFrames();
         ssize_t avail =  (mIsOut) ? adjustableSize - filled : filled;
         if (avail < 0) {
             avail = 0;
@@ -357,20 +379,6 @@
             (mFrameCountP2 - 1);
 }
 
-size_t ClientProxy::setBufferSizeInFrames(size_t size)
-{
-    // TODO set minimum to 2X the fast mixer buffer size.
-    size_t minimum = 128 * 2; // arbitrary
-    size_t maximum = frameCount();
-    if (size < minimum) {
-        size = minimum;
-    } else if (size > maximum) {
-        size = maximum;
-    }
-    mBufferSizeInFrames = size;
-    return size;
-}
-
 // ---------------------------------------------------------------------------
 
 void AudioTrackClientProxy::flush()
@@ -601,6 +609,7 @@
       mAvailToClient(0), mFlush(0), mReleased(0)
     , mTimestampMutator(&cblk->mExtendedTimestampQueue)
 {
+    cblk->mBufferSizeInFrames = frameCount;
 }
 
 status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8b49062..a75ca77 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -617,7 +617,7 @@
         return true;
     }
 
-    if (framesReady() >= mFrameCount ||
+    if (framesReady() >= mServerProxy->getBufferSizeInFrames() ||
             (mCblk->mFlags & CBLK_FORCEREADY)) {
         mFillingUpStatus = FS_FILLED;
         android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);