Merge "MediaPlayer: overhaul buffering monitor scheme."
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index fe4611c..38adb03 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -305,6 +305,11 @@
      */
             uint32_t    latency() const     { return mLatency; }
 
+    /* Returns the number of application-level buffer underruns
+     * since the AudioTrack was created.
+     */
+            uint32_t    getUnderrunCount() const;
+
     /* getters, see constructors and set() */
 
             audio_stream_type_t streamType() const;
@@ -320,6 +325,25 @@
             uint32_t    channelCount() const { return mChannelCount; }
             size_t      frameCount() const  { return mFrameCount; }
 
+    /* Return effective size of audio buffer that an application writes to
+     * or a negative error if the track is uninitialized.
+     */
+            ssize_t     getBufferSizeInFrames();
+
+    /* Set the effective size of audio buffer that an application writes to.
+     * This is used to determine the amount of available room in the buffer,
+     * which determines when a write will block.
+     * This allows an application to raise and lower the audio latency.
+     * The requested size may be adjusted so that it is
+     * greater or equal to the absolute minimum and
+     * less than or equal to the getBufferCapacityInFrames().
+     * It may also be adjusted slightly for internal reasons.
+     *
+     * Return the final size or a negative error if the track is unitialized
+     * or does not support variable sizes.
+     */
+            ssize_t     setBufferSizeInFrames(size_t size);
+
     /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
             sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
 
@@ -784,6 +808,8 @@
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreTrack_l(const char *from);
 
+            uint32_t    getUnderrunCount_l() const;
+
             bool     isOffloaded() const;
             bool     isDirect() const;
             bool     isOffloadedOrDirect() const;
@@ -811,14 +837,18 @@
     audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutput()
 
     sp<AudioTrackThread>    mAudioTrackThread;
+    bool                    mThreadCanCallJava;
 
     float                   mVolume[2];
     float                   mSendLevel;
     mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it
     uint32_t                mOriginalSampleRate;
     AudioPlaybackRate       mPlaybackRate;
-    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
-                                                    // reported back by AudioFlinger to the client
+
+    // Corresponds to current IAudioTrack, value is reported back by AudioFlinger to the client.
+    // This allocated buffer size is maintained by the proxy.
+    size_t                  mFrameCount;            // maximum size of buffer
+
     size_t                  mReqFrameCount;         // frame count to request the first or next time
                                                     // a new IAudioTrack is needed, non-decreasing
 
@@ -911,6 +941,8 @@
     bool                    mRetrogradeMotionReported; // reduce log spam
     AudioTimestamp          mPreviousTimestamp;     // used to detect retrograde motion
 
+    uint32_t                mUnderrunCountOffset;   // updated when restoring tracks
+
     audio_output_flags_t    mFlags;
         // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
         // mLock must be held to read or write those bits reliably.
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index e458f3c..770f007 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -59,7 +59,8 @@
     volatile int32_t mRear;     // written by producer (output: client, input: server)
     volatile int32_t mFlush;    // incremented by client to indicate a request to flush;
                                 // server notices and discards all data between mFront and mRear
-    volatile uint32_t mUnderrunFrames;  // server increments for each unavailable but desired frame
+    volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame
+    volatile uint32_t mUnderrunCount;  // server increments for each underrun occurrence
 };
 
 // Represents a single state of an AudioTrack that was created in static mode (shared memory buffer
@@ -174,8 +175,6 @@
 
     volatile    int32_t     mFlags;         // combinations of CBLK_*
 
-                // Cache line boundary (32 bytes)
-
 public:
                 union {
                     AudioTrackSharedStreaming   mStreaming;
@@ -204,6 +203,8 @@
         size_t  mNonContig;             // number of additional non-contiguous frames available
     };
 
+    size_t frameCount() const { return mFrameCount; }
+
 protected:
     // These refer to shared memory, and are virtual addresses with respect to the current process.
     // They may have different virtual addresses within the other process.
@@ -285,7 +286,7 @@
         return mEpoch + mCblk->mServer;
     }
 
-    void             setEpoch(const Modulo<uint32_t> &epoch) {
+    void        setEpoch(const Modulo<uint32_t> &epoch) {
         mEpoch = epoch;
     }
 
@@ -305,6 +306,15 @@
         return mEpoch;
     }
 
+    size_t      getBufferSizeInFrames() const { return mBufferSizeInFrames; }
+    // See documentation for AudioTrack.setBufferSizeInFrames()
+    size_t      setBufferSizeInFrames(size_t requestedSize);
+
+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:
     Modulo<uint32_t> mEpoch;
 };
@@ -347,6 +357,9 @@
     virtual uint32_t    getUnderrunFrames() const {
         return mCblk->u.mStreaming.mUnderrunFrames;
     }
+    virtual uint32_t    getUnderrunCount() const {
+        return mCblk->u.mStreaming.mUnderrunCount;
+    }
 
     bool        clearStreamEndDone();   // and return previous value
 
@@ -471,7 +484,8 @@
     AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
         : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
-          mPlaybackRateObserver(&cblk->mPlaybackRateQueue) {
+          mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
+          mUnderrunCount(0), mUnderrunning(false) {
         mCblk->mSampleRate = sampleRate;
         mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
     }
@@ -514,6 +528,10 @@
 private:
     AudioPlaybackRate             mPlaybackRate;  // last observed playback rate
     PlaybackRateQueue::Observer   mPlaybackRateObserver;
+
+    // The server keeps a copy here where it is safe from the client.
+    uint32_t                      mUnderrunCount; // echoed to mCblk
+    bool                          mUnderrunning;  // used to detect edge of underrun
 };
 
 class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 5e14940..a13d53a 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -288,6 +288,8 @@
           streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
           sessionId, transferType, uid, pid);
 
+    mThreadCanCallJava = threadCanCallJava;
+
     switch (transferType) {
     case TRANSFER_DEFAULT:
         if (sharedBuffer != 0) {
@@ -356,6 +358,9 @@
         if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
             flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
         }
+        if ((mAttributes.flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
+            flags = (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_FAST);
+        }
     }
 
     // these below should probably come from the audioFlinger too...
@@ -493,6 +498,7 @@
     mPreviousTimestampValid = false;
     mTimestampStartupGlitchReported = false;
     mRetrogradeMotionReported = false;
+    mUnderrunCountOffset = 0;
 
     return NO_ERROR;
 }
@@ -855,6 +861,31 @@
     return mPlaybackRate;
 }
 
+ssize_t AudioTrack::getBufferSizeInFrames()
+{
+    AutoMutex lock(mLock);
+    if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+        return NO_INIT;
+    }
+    return mProxy->getBufferSizeInFrames();
+}
+
+ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
+{
+    AutoMutex lock(mLock);
+    if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+        return NO_INIT;
+    }
+    // Reject if timed track or compressed audio.
+    if (mIsTimed || !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);
+}
+
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
 {
     if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
@@ -1170,20 +1201,26 @@
     }
     // Client decides whether the track is TIMED (see below), but can only express a preference
     // for FAST.  Server will perform additional tests.
-    if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
+    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+        bool useCaseAllowed =
             // either of these use cases:
             // use case 1: shared buffer
             (mSharedBuffer != 0) ||
             // use case 2: callback transfer mode
             (mTransfer == TRANSFER_CALLBACK) ||
             // use case 3: obtain/release mode
-            (mTransfer == TRANSFER_OBTAIN)) &&
-            // matching sample rate
-            (mSampleRate == mAfSampleRate))) {
-        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, output %u Hz",
+            (mTransfer == TRANSFER_OBTAIN) ||
+            // use case 4: synchronous write
+            ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+        // sample rates must also match
+        bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate);
+        if (!fastAllowed) {
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d,"
+                "track %u Hz, output %u Hz",
                 mTransfer, mSampleRate, mAfSampleRate);
-        // once denied, do not request again if IAudioTrack is re-created
-        mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+            // once denied, do not request again if IAudioTrack is re-created
+            mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+        }
     }
 
     // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
@@ -1254,7 +1291,7 @@
     pid_t tid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         trackFlags |= IAudioFlinger::TRACK_FAST;
-        if (mAudioTrackThread != 0) {
+        if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
             tid = mAudioTrackThread->getTid();
         }
     }
@@ -1328,7 +1365,9 @@
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         if (trackFlags & IAudioFlinger::TRACK_FAST) {
             ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount);
-            mAwaitBoost = true;
+            if (!mThreadCanCallJava) {
+                mAwaitBoost = true;
+            }
         } else {
             ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
             // once denied, do not request again if IAudioTrack is re-created
@@ -2112,6 +2151,9 @@
         return DEAD_OBJECT;
     }
 
+    // Save so we can return count since creation.
+    mUnderrunCountOffset = getUnderrunCount_l();
+
     // save the old static buffer position
     size_t bufferPosition = 0;
     int loopCount = 0;
@@ -2427,6 +2469,17 @@
     return NO_ERROR;
 }
 
+uint32_t AudioTrack::getUnderrunCount() const
+{
+    AutoMutex lock(mLock);
+    return getUnderrunCount_l();
+}
+
+uint32_t AudioTrack::getUnderrunCount_l() const
+{
+    return mProxy->getUnderrunCount() + mUnderrunCountOffset;
+}
+
 uint32_t AudioTrack::getUnderrunFrames() const
 {
     AutoMutex lock(mLock);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 9fad500..2742db0 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -66,7 +66,9 @@
 
 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), mEpoch(0)
+    : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
+    , mBufferSizeInFrames(frameCount)
+    , mEpoch(0)
 {
 }
 
@@ -151,6 +153,7 @@
             rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
             front = cblk->u.mStreaming.mFront;
         }
+        // write to rear, read from front
         ssize_t filled = rear - front;
         // pipe should not be overfull
         if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
@@ -166,11 +169,17 @@
             cblk->u.mStreaming.mFront = rear;
             (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
         }
-        // don't allow filling pipe beyond the nominal size
-        size_t avail = mIsOut ? mFrameCount - filled : filled;
-        if (avail > 0) {
+        // Don't allow filling pipe beyond the user settable size.
+        // 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 avail =  (mIsOut) ? adjustableSize - filled : filled;
+        if (avail < 0) {
+            avail = 0;
+        } else if (avail > 0) {
             // 'avail' may be non-contiguous, so return only the first contiguous chunk
-            size_t part1;
+            ssize_t part1;
             if (mIsOut) {
                 rear &= mFrameCountP2 - 1;
                 part1 = mFrameCountP2 - rear;
@@ -181,10 +190,10 @@
             if (part1 > avail) {
                 part1 = avail;
             }
-            if (part1 > buffer->mFrameCount) {
+            if (part1 > (ssize_t) buffer->mFrameCount) {
                 part1 = buffer->mFrameCount;
             }
-            buffer->mFrameCount = part1;
+            buffer->mFrameCount = (size_t) part1;
             buffer->mRaw = part1 > 0 ?
                     &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
             buffer->mNonContig = avail - part1;
@@ -347,6 +356,20 @@
             (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()
@@ -781,10 +804,25 @@
 void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
 {
     audio_track_cblk_t* cblk = mCblk;
-    cblk->u.mStreaming.mUnderrunFrames += frameCount;
+    if (frameCount > 0) {
+        cblk->u.mStreaming.mUnderrunFrames += frameCount;
 
-    // FIXME also wake futex so that underrun is noticed more quickly
-    (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
+        if (!mUnderrunning) { // start of underrun?
+            mUnderrunCount++;
+            cblk->u.mStreaming.mUnderrunCount = mUnderrunCount;
+            mUnderrunning = true;
+            ALOGV("tallyUnderrunFrames(%3u) at uf = %u, bump mUnderrunCount = %u",
+                frameCount, cblk->u.mStreaming.mUnderrunFrames, mUnderrunCount);
+        }
+
+        // FIXME also wake futex so that underrun is noticed more quickly
+        (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
+    } else {
+        ALOGV_IF(mUnderrunning,
+            "tallyUnderrunFrames(%3u) at uf = %u, underrun finished",
+            frameCount, cblk->u.mStreaming.mUnderrunFrames);
+        mUnderrunning = false; // so we can detect the next edge
+    }
 }
 
 AudioPlaybackRate AudioTrackServerProxy::getPlaybackRate()
@@ -1010,7 +1048,7 @@
     buffer->mNonContig = 0;
 }
 
-void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
+void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
 {
     // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
     // we don't have a location to count underrun frames.  The underrun frame counter
@@ -1018,7 +1056,9 @@
     // possible for static buffer tracks other than at end of buffer, so this is not a loss.
 
     // FIXME also wake futex so that underrun is noticed more quickly
-    (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+    if (frameCount > 0) {
+        (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+    }
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 65166b0..0458554 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3788,6 +3788,8 @@
                     recentUnderruns > 0) {
                 // FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun
                 track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount);
+            } else {
+                track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
             }
 
             // This is similar to the state machine for normal tracks,
@@ -4157,7 +4159,10 @@
                 ALOGV("track(%p) underrun,  framesReady(%zu) < framesDesired(%zd)",
                         track, framesReady, desiredFrames);
                 track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+            } else {
+                track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
             }
+
             // clear effect chain input buffer if an active track underruns to avoid sending
             // previous audio buffer again to effects
             chain = getEffectChain_l(track->sessionId());
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b1638ea..c753afd 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -600,7 +600,10 @@
     buffer->raw = buf.mRaw;
     if (buf.mFrameCount == 0) {
         mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+    } else {
+        mAudioTrackServerProxy->tallyUnderrunFrames(0);
     }
+
     return status;
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index e3ff9ae..a3536e5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -294,8 +294,15 @@
         if (strlen(devTag) != 0) {
             audio_devices_t type;
             if (DeviceConverter::fromString(devTag, type)) {
-                sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
-                devices.add(dev);
+                uint32_t inBit = type & AUDIO_DEVICE_BIT_IN;
+                type &= ~AUDIO_DEVICE_BIT_IN;
+                while (type) {
+                  audio_devices_t singleType =
+                        inBit | (1 << (31 - __builtin_clz(type)));
+                    type &= ~singleType;
+                    sp<DeviceDescriptor> dev = new DeviceDescriptor(singleType);
+                    devices.add(dev);
+                }
             } else {
                 sp<DeviceDescriptor> deviceDesc =
                         declaredDevices.getDeviceFromTagName(String8(devTag));