aaudio: use xruns detected in the service

The service knows when an actual xrun occurs so we pass
that value to the client.

Bug: 38512417
Test: write_sine_callback -pl -n1 -s20 -c2 -u
Change-Id: I9e5ff1edd2e9378957309280162d7cda855f5adb
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 57241a1..b031888 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -49,7 +49,7 @@
     memset(mOutputBuffer, 0, mBufferSizeInBytes);
 }
 
-bool AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
+int32_t AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
     WrappingBuffer wrappingBuffer;
     float *destination = mOutputBuffer;
 
@@ -105,7 +105,7 @@
     ATRACE_END();
 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */
 
-    return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
+    return (framesDesired - framesLeft); // framesRead
 }
 
 void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) {
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index 5625d4d..d5abc5b 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -36,15 +36,17 @@
      * @param streamIndex for marking stream variables in systrace
      * @param fifo to read from
      * @param allowUnderflow if true then allow mixer to advance read index past the write index
-     * @return true if actually underflowed
+     * @return frames read from this stream
      */
-    bool mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
-
-    void mixPart(float *destination, float *source, int32_t numFrames);
+    int32_t mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
 
     float *getOutputBuffer();
 
+    int32_t getFramesPerBurst() const { return mFramesPerBurst; }
+
 private:
+    void mixPart(float *destination, float *source, int32_t numFrames);
+
     float   *mOutputBuffer = nullptr;
     int32_t  mSamplesPerFrame = 0;
     int32_t  mFramesPerBurst = 0;
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index f902bef..efac788 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -58,7 +58,6 @@
 // Read data from the shared MMAP stream and then distribute it to the client streams.
 void *AAudioServiceEndpointCapture::callbackLoop() {
     ALOGD("callbackLoop() entering");
-    int32_t underflowCount = 0;
     aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
 
@@ -102,9 +101,10 @@
                             int64_t positionOffset = mmapFramesRead - clientFramesWritten;
                             streamShared->setTimestampPositionOffset(positionOffset);
 
+                            // Is the buffer too full to write a burst?
                             if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                                getFramesPerBurst()) {
-                                underflowCount++;
+                                    getFramesPerBurst()) {
+                                streamShared->incrementXRunCount();
                             } else {
                                 fifo->write(mDistributionBuffer, getFramesPerBurst());
                             }
@@ -125,6 +125,6 @@
         }
     }
 
-    ALOGD("callbackLoop() exiting, %d underflows", underflowCount);
+    ALOGD("callbackLoop() exiting");
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index c2feb6b..2601f3f 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -34,6 +34,7 @@
 #include "AAudioServiceStreamShared.h"
 #include "AAudioServiceEndpointPlay.h"
 #include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceStreamBase.h"
 
 using namespace android;  // TODO just import names needed
 using namespace aaudio;   // TODO just import names needed
@@ -108,9 +109,19 @@
                         int64_t positionOffset = mmapFramesWritten - clientFramesRead;
                         streamShared->setTimestampPositionOffset(positionOffset);
 
-                        bool underflowed = mMixer.mix(index, fifo, allowUnderflow);
-                        if (underflowed) {
-                            streamShared->incrementXRunCount();
+                        int32_t framesMixed = mMixer.mix(index, fifo, allowUnderflow);
+
+                        if (streamShared->isFlowing()) {
+                            // Consider it an underflow if we got less than a burst
+                            // after the data started flowing.
+                            bool underflowed = allowUnderflow
+                                               && framesMixed < mMixer.getFramesPerBurst();
+                            if (underflowed) {
+                                streamShared->incrementXRunCount();
+                            }
+                        } else if (framesMixed > 0) {
+                            // Mark beginning of data flow after a start.
+                            streamShared->setFlowing(true);
                         }
                         clientFramesRead = fifo->getReadCounter();
                     }
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 820ed28..6af9e7e 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -47,6 +47,7 @@
            << std::setfill('0') << std::setw(8)
            << std::hex << mStreamInternal->getServiceHandle()
            << std::dec << std::setfill(' ');
+    result << ", XRuns = " << mStreamInternal->getXRunCount();
     result << "\n";
     result << "    Running Stream Count: " << mRunningStreamCount << "\n";
 
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 6652cc9..635b45c 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -172,6 +172,8 @@
         goto error;
     }
 
+    setFlowing(false);
+
     // Start with fresh presentation timestamps.
     mAtomicTimestamp.clear();
 
@@ -311,12 +313,19 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
-                                               double  dataDouble,
-                                               int64_t dataLong) {
+                                                          double  dataDouble) {
     AAudioServiceMessage command;
     command.what = AAudioServiceMessage::code::EVENT;
     command.event.event = event;
     command.event.dataDouble = dataDouble;
+    return writeUpMessageQueue(&command);
+}
+
+aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
+                                                          int64_t dataLong) {
+    AAudioServiceMessage command;
+    command.what = AAudioServiceMessage::code::EVENT;
+    command.event.event = event;
     command.event.dataLong = dataLong;
     return writeUpMessageQueue(&command);
 }
@@ -336,6 +345,10 @@
     }
 }
 
+aaudio_result_t AAudioServiceStreamBase::sendXRunCount(int32_t xRunCount) {
+    return sendServiceEvent(AAUDIO_SERVICE_EVENT_XRUN, (int64_t) xRunCount);
+}
+
 aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
     AAudioServiceMessage command;
     // Send a timestamp for the clock model.
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index af435b4..29987f6 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -129,11 +129,15 @@
     // -------------------------------------------------------------------
 
     /**
-     * Send a message to the client.
+     * Send a message to the client with an int64_t data value.
      */
     aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
-                                     double  dataDouble = 0.0,
                                      int64_t dataLong = 0);
+    /**
+     * Send a message to the client with an double data value.
+     */
+    aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
+                                     double  dataDouble);
 
     /**
      * Fill in a parcelable description of stream.
@@ -182,6 +186,19 @@
 
     void onVolumeChanged(float volume);
 
+    /**
+     * Set false when the stream is started.
+     * Set true when data is first read from the stream.
+     * @param b
+     */
+    void setFlowing(bool b) {
+        mFlowing = b;
+    }
+
+    bool isFlowing() const {
+        return mFlowing;
+    }
+
 protected:
 
     /**
@@ -204,6 +221,8 @@
 
     aaudio_result_t sendCurrentTimestamp();
 
+    aaudio_result_t sendXRunCount(int32_t xRunCount);
+
     /**
      * @param positionFrames
      * @param timeNanos
@@ -237,6 +256,8 @@
 
 private:
     aaudio_handle_t         mHandle = -1;
+
+    bool                    mFlowing = false;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 8499ea5..3b12e61 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -1,4 +1,4 @@
-/*
+ /*
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -80,7 +80,7 @@
     }
 
     void incrementXRunCount() {
-        mXRunCount++;
+        sendXRunCount(++mXRunCount);
     }
 
     int32_t getXRunCount() const {