audio HAL: remote mic capture improvements

Change capture period from 10ms to 20ms to avoid creating a fast capture
thread.
Extend period count to 32 to reduce risk of underrun in the ALSA PCM driver.
Add throttling in AudioStreamIn::read() to smooth the capture rate.

Bug: 37475487
Test: Voice search from remote.
Change-Id: I3ea1cc135f8fa45c33345ab2fd25b7526a690602
diff --git a/libaudio/AudioHardwareInput.cpp b/libaudio/AudioHardwareInput.cpp
index 6a7a9f4..eef0e89 100644
--- a/libaudio/AudioHardwareInput.cpp
+++ b/libaudio/AudioHardwareInput.cpp
@@ -76,7 +76,7 @@
 }
 
 // milliseconds per ALSA period
-const uint32_t AudioHardwareInput::kPeriodMsec = 10;
+const uint32_t AudioHardwareInput::kPeriodMsec = 20;
 
 size_t AudioHardwareInput::calculateInputBufferSize(uint32_t outputSampleRate,
                                                     audio_format_t format,
diff --git a/libaudio/AudioStreamIn.cpp b/libaudio/AudioStreamIn.cpp
index 89df69a..36156aa 100644
--- a/libaudio/AudioStreamIn.cpp
+++ b/libaudio/AudioStreamIn.cpp
@@ -43,7 +43,7 @@
 const uint32_t AudioStreamIn::kChannelMask = AUDIO_CHANNEL_IN_MONO;
 
 // number of periods in the ALSA buffer
-const int AudioStreamIn::kPeriodCount = 4;
+const int AudioStreamIn::kPeriodCount = 32;
 
 AudioStreamIn::AudioStreamIn(AudioHardwareInput& owner)
     : mOwnerHAL(owner)
@@ -58,6 +58,9 @@
     , mInputSource(AUDIO_SOURCE_DEFAULT)
     , mReadStatus(0)
     , mFramesIn(0)
+    , mLastReadFinishedNs(-1)
+    , mLastBytesRead(0)
+    , mMinAllowedReadTimeNs(0)
 {
     struct resampler_buffer_provider& provider =
             mResamplerProviderWrapper.provider;
@@ -282,12 +285,37 @@
         // if we have never returned any data from an actual device and need
         // to synth on the first call to read)
         usleep(bytes * 1000000 / getFrameSize() / mRequestedSampleRate);
+        mLastReadFinishedNs = -1;
     } else {
         bool mute;
         mOwnerHAL.getMicMute(&mute);
         if (mute) {
             memset(buffer, 0, bytes);
         }
+
+        nsecs_t now = systemTime();
+
+        if (mLastReadFinishedNs != -1) {
+            const nsecs_t kMinsleeptimeNs = 1000000; // don't sleep less than 1ms
+            const nsecs_t deltaNs = now - mLastReadFinishedNs;
+
+            if (bytes != mLastBytesRead) {
+                mMinAllowedReadTimeNs =
+                        (((nsecs_t)bytes * 1000000000) / getFrameSize()) / mRequestedSampleRate / 2;
+                mLastBytesRead = bytes;
+            }
+
+            // Make sure total read time is at least the duration corresponding to half the amount
+            // of data requested.
+            // Note: deltaNs is always > 0 here
+            if (mMinAllowedReadTimeNs > deltaNs + kMinsleeptimeNs) {
+                usleep((mMinAllowedReadTimeNs - deltaNs) / 1000);
+                // Throttle must be attributed to the previous read time to allow
+                // back-to-back throttling.
+                now = systemTime();
+            }
+        }
+        mLastReadFinishedNs = now;
     }
 
     return bytes;
@@ -375,6 +403,9 @@
     }
     mBuffer = new int16_t[mBufferSize / sizeof(uint16_t)];
 
+    mLastReadFinishedNs = -1;
+    mLastBytesRead = 0;
+
     if (mResampler) {
         release_resampler(mResampler);
         mResampler = NULL;
diff --git a/libaudio/AudioStreamIn.h b/libaudio/AudioStreamIn.h
index 8c2d444..1fe4410 100644
--- a/libaudio/AudioStreamIn.h
+++ b/libaudio/AudioStreamIn.h
@@ -115,6 +115,9 @@
     int               mInputSource;
     int               mReadStatus;
     unsigned int      mFramesIn;
+    nsecs_t           mLastReadFinishedNs;
+    size_t            mLastBytesRead;
+    nsecs_t           mMinAllowedReadTimeNs;
 };
 
 }; // namespace android