Flush FastCapture PipeReader when starting after stop

Discards stale frames.

Bug: 30199985
Change-Id: Ie93a3784bf052aba6989d2ff1be92b1980b0c207
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index 120de4f..c22c476 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -266,6 +266,17 @@
     //              One or more frames were lost due to overrun, try again to read more recent data.
     virtual ssize_t read(void *buffer, size_t count) = 0;
 
+    // Flush data from buffer.  There is no notion of overrun as all data is dropped.
+    // Flushed frames also count towards frames read.
+    //
+    // Return value:
+    //  >= 0    Number of frames successfully flushed
+    //  < 0     status_t error occurred
+    // Errors:
+    //  NEGOTIATE         (Re-)negotiation is needed.
+    //  INVALID_OPERATION Not implemented
+    virtual ssize_t flush() { return INVALID_OPERATION; }
+
     // Transfer data from source using a series of callbacks.  More suitable for zero-fill,
     // synthesis, and non-contiguous transfers (e.g. circular buffer or readv).
     // Inputs:
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
index 7c733ad..00c2b3c 100644
--- a/include/media/nbaio/PipeReader.h
+++ b/include/media/nbaio/PipeReader.h
@@ -47,6 +47,8 @@
 
     virtual ssize_t read(void *buffer, size_t count);
 
+    virtual ssize_t flush();
+
     // NBAIO_Source end
 
 #if 0   // until necessary
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index a879647..799e435 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -45,6 +45,7 @@
     ALOG_ASSERT(readers > 0);
 }
 
+__attribute__((no_sanitize("integer")))
 ssize_t PipeReader::availableToRead()
 {
     if (CC_UNLIKELY(!mNegotiated)) {
@@ -64,6 +65,7 @@
     return avail;
 }
 
+__attribute__((no_sanitize("integer")))
 ssize_t PipeReader::read(void *buffer, size_t count)
 {
     ssize_t avail = availableToRead();
@@ -97,4 +99,19 @@
     return red;
 }
 
+__attribute__((no_sanitize("integer")))
+ssize_t PipeReader::flush()
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    const int32_t rear = android_atomic_acquire_load(&mPipe.mRear);
+    const size_t flushed = rear - mFront;
+    // We don't check if flushed > mPipe.mMaxFrames (an overrun occurred) as the
+    // distinction is unimportant; all data is dropped.
+    mFront = rear;
+    mFramesRead += flushed;  // we consider flushed frames as read.
+    return flushed;
+}
+
 }   // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 475704f..56a7257 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6459,6 +6459,16 @@
         }
     }
     mInput->stream->common.standby(&mInput->stream->common);
+
+    // If going into standby, flush the pipe source.
+    if (mPipeSource.get() != nullptr) {
+        const ssize_t flushed = mPipeSource->flush();
+        if (flushed > 0) {
+            ALOGV("Input standby flushed PipeSource %zd frames", flushed);
+            mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += flushed;
+            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+        }
+    }
 }
 
 // RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held