Pull muted tab audio on a RT thread in the audio process.

If tab capture audio is muted locally, then it's rendererd as a fake audio
stream [1]. Fake audio streams run on the AudioManager worker task runner
[2]. It runs on a normal prio thread in the audio process [3].

However, its loopback runs (as it should) on a RT loopback worker [4].

When the system is under a strain, the normal prio fake worker cannot keep
up and it results in loopback stream passing empty buffers to the client
(crackling audio).

The only case of using a worker task runner in the audio process is
rendering fake audio streams, and fake audio streams are only used for
pulling the muted tab audio from the renderer.

While in some cases it may be beneficial to pull the muted audio on a
normal prio thread (power saving), in other cases (tab loopback like above,
probably video playback?) it's better to use a RT prio for that.

This CL
(1) Proposes to change the worker task runner of the audio process to RT
priority;
(2) Still keeps a dedicated loopback worker (see above, also RT priority):
on one hand, we can probably get away with a single RT worker for both,
but on the other hand, it looks risky to run "pull" (playback) and
"push" (loopback) models on the same thread. (I'm being concervative here
and open to consider using a single worker for both if the reviewers feel
strongly about that)




[1] https://source.chromium.org/chromium/chromium/src/+/master:services/audio/output_controller.cc;l=227
[2] https://source.chromium.org/chromium/chromium/src/+/master:media/audio/fake_audio_output_stream.cc;l=27
[3] https://source.chromium.org/chromium/chromium/src/+/master:services/audio/owning_audio_manager_accessor.cc;l=118;drc=a4708b724062f17824815b896c3aaa43825128f8
[4] https://source.chromium.org/chromium/chromium/src/+/master:services/audio/stream_factory.cc;drc=ca84e805e22c77c887a016d8bd3ef047687b8871;l=170

Bug: 1130375
Change-Id: Ic0a0c9143f170fc3c9ff0c30dff49673cd9354de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2749294
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Olga Sharonova <olka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#861964}
diff --git a/services/audio/delay_buffer.cc b/services/audio/delay_buffer.cc
index 17d2a04b..0254fad 100644
--- a/services/audio/delay_buffer.cc
+++ b/services/audio/delay_buffer.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/numerics/safe_conversions.h"
+#include "base/trace_event/trace_event.h"
 #include "media/base/audio_bus.h"
 #include "media/base/vector_math.h"
 
@@ -62,6 +63,9 @@
     // If attempting to read past the end of the recorded signal, zero-pad the
     // rest of the output and return.
     if (chunks_.empty()) {
+      TRACE_EVENT_INSTANT1("audio", "DelayBuffer::Read underrun",
+                           TRACE_EVENT_SCOPE_THREAD, "frames missing",
+                           frames_remaining);
       output_bus->ZeroFramesPartial(dest_offset, frames_remaining);
       return;
     }
@@ -80,6 +84,9 @@
       const int frames_to_zero_fill = (source_offset + frames_remaining <= 0)
                                           ? frames_remaining
                                           : -source_offset;
+      TRACE_EVENT_INSTANT1("audio", "DelayBuffer::Read gap",
+                           TRACE_EVENT_SCOPE_THREAD, "frames missing",
+                           frames_to_zero_fill);
       output_bus->ZeroFramesPartial(dest_offset, frames_to_zero_fill);
       frames_remaining -= frames_to_zero_fill;
       continue;
diff --git a/services/audio/owning_audio_manager_accessor.cc b/services/audio/owning_audio_manager_accessor.cc
index 9ecffa35..18b8330 100644
--- a/services/audio/owning_audio_manager_accessor.cc
+++ b/services/audio/owning_audio_manager_accessor.cc
@@ -115,7 +115,10 @@
       task_runner_->BelongsToCurrentThread() ||
       (worker_task_runner_ && worker_task_runner_->BelongsToCurrentThread()));
   if (!worker_task_runner_) {
-    CHECK(worker_thread_.Start());
+    base::Thread::Options options;
+    options.timer_slack = base::TIMER_SLACK_NONE;
+    options.priority = base::ThreadPriority::REALTIME_AUDIO;
+    CHECK(worker_thread_.StartWithOptions(options));
     worker_task_runner_ = worker_thread_.task_runner();
   }
   return worker_task_runner_.get();