Fix secondary output under&over run

There were three issues with the implementation
of Audio Playback Capture patches on secondary outputs.

1) Patch tracks were always forced to be ready, even if there were not
enough audio to be played. That led to playing partial buffers if the
source output had smaller (time wise) buffer than the secondary output.

This is fixed by avoiding setting CBLK_FORCEREADY on every buffer push
from the primary output thread.

2) After 1 is fixed, the patch tracks now behave like regular (non fast)
tracks. This means that the track only starts when it is full.
That leads to overrun on startup as the primary and secondary outputs
usually do not have the same write period.

What makes the issue worst is that Remote submix has a fixed buffer in bytes,
so its write period changes depending on sample rate contrary to the
primary HAL which pulls with fixed time periods (usually 20/40ms).

This patch solution is to introduce a ready threshold. The track will be
considered ready to be active if there are more than frames in its buffer.

To avoid changing previous latency behaviour except for APC,
legacy tracks have this threshold set to their buffer size and
non APC patch tracks have it set to 1, similar to setting
CBLK_FORCEREADY.

3) The patch track buffer size calculation of the patch track did not take
into account primary and secondary output could be of different sampling
rate.
This mean that the patch track buffer was usually too small as the
secondary output usually had smaller sampling rate (Live caption
requests 16kHz) than the track (music usually plays in 48kHz).
This made the two problems even worst.

This was easily fixed by scaling the buffer size with each side sample rate.

Bug: 136691300
Test: play audio
      adb shell audiorecorder  --target /data/file1.raw
      # Check that the recorded file has no underrun
Change-Id: Ib2846b2827afd1b953d4a25acb18c7cadf57cd3e
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 355d945..9b0872e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -810,7 +810,33 @@
                     continue;
                 }
 
-                size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount());
+                size_t sourceFrameCount = thread->frameCount() * output.sampleRate
+                                          / thread->sampleRate();
+                size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate
+                                          / secondaryThread->sampleRate();
+                // If the secondary output has just been opened, the first secondaryThread write
+                // will not block as it will fill the empty startup buffer of the HAL,
+                // so a second sink buffer needs to be ready for the immediate next blocking write.
+                // Additionally, have a margin of one main thread buffer as the scheduling jitter
+                // can reorder the writes (eg if thread A&B have the same write intervale,
+                // the scheduler could schedule AB...BA)
+                size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
+                // Total secondary output buffer must be at least as the read frames plus
+                // the margin of a few buffers on both sides in case the
+                // threads scheduling has some jitter.
+                // That value should not impact latency as the secondary track is started before
+                // its buffer is full, see frameCountToBeReady.
+                size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
+                // The frameCount should also not be smaller than the secondary thread min frame
+                // count
+                size_t minFrameCount = AudioSystem::calculateMinFrameCount(
+                            [&] { Mutex::Autolock _l(secondaryThread->mLock);
+                                  return secondaryThread->latency_l(); }(),
+                            secondaryThread->mNormalFrameCount,
+                            secondaryThread->mSampleRate,
+                            output.sampleRate,
+                            input.speed);
+                frameCount = std::max(frameCount, minFrameCount);
 
                 using namespace std::chrono_literals;
                 auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
@@ -843,7 +869,8 @@
                                                                patchRecord->buffer(),
                                                                patchRecord->bufferSize(),
                                                                outputFlags,
-                                                               0ns /* timeout */);
+                                                               0ns /* timeout */,
+                                                               frameCountToBeReady);
                 status = patchTrack->initCheck();
                 if (status != NO_ERROR) {
                     ALOGE("Secondary output patchTrack init failed: %d", status);