Commit 33783dd6 authored by Yuri Wiitala's avatar Yuri Wiitala Committed by Commit Bot

[AudioService] Use realtime thread for loopback worker.

Instead of using the AudioManager worker thread, which has normal thread
priority; use a realtime thread for audio loopback. This is needed
because the GenerateMoreAudio() tasks were executing way too late during
low-available-CPU situations, and this was causing audio underruns and
lots of cut-outs/glitching for the end user.

Bug: 960161
Change-Id: I4350aab93a1678c57a8e8769dc7852a2d181be39
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1602114Reviewed-by: default avatarYuri Wiitala <miu@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Commit-Queue: Yuri Wiitala <miu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#658322}
parent 7fa3c701
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
namespace audio { namespace audio {
StreamFactory::StreamFactory(media::AudioManager* audio_manager) StreamFactory::StreamFactory(media::AudioManager* audio_manager)
: audio_manager_(audio_manager) { : audio_manager_(audio_manager),
loopback_worker_thread_("Loopback Worker") {
magic_bytes_ = 0x600DC0DEu; magic_bytes_ = 0x600DC0DEu;
SetStateForCrashing("constructed"); SetStateForCrashing("constructed");
} }
...@@ -189,13 +190,40 @@ void StreamFactory::CreateLoopbackStream( ...@@ -189,13 +190,40 @@ void StreamFactory::CreateLoopbackStream(
group_id.GetLowForSerialization(), "params", group_id.GetLowForSerialization(), "params",
params.AsHumanReadableString()); params.AsHumanReadableString());
// All LoopbackStreams share a single realtime worker thread. This is because
// the execution timing of scheduled tasks must be precise, and top priority
// should be given to the smooth continuous flow of audio while in low-CPU
// situations; all to avoid glitches. The thread is started just before the
// first LoopbackStream will be created, and stopped after all LoopbackStreams
// are gone.
scoped_refptr<base::SequencedTaskRunner> task_runner;
if (loopback_worker_thread_.IsRunning()) {
task_runner = loopback_worker_thread_.task_runner();
} else {
TRACE_EVENT_BEGIN0("audio", "Start Loopback Worker");
base::Thread::Options options;
options.timer_slack = base::TIMER_SLACK_NONE;
options.priority = base::ThreadPriority::REALTIME_AUDIO;
if (loopback_worker_thread_.StartWithOptions(options)) {
task_runner = loopback_worker_thread_.task_runner();
TRACE_EVENT_END1("audio", "Start Loopback Worker", "success", true);
} else {
// Something about this platform or its current environment has prevented
// a realtime audio thread from being started. Fall-back to using the
// AudioManager worker thread.
LOG(ERROR) << "Unable to start realtime loopback worker thread.";
task_runner = audio_manager_->GetWorkerTaskRunner();
TRACE_EVENT_END1("audio", "Start Loopback Worker", "success", false);
}
}
auto stream = std::make_unique<LoopbackStream>( auto stream = std::make_unique<LoopbackStream>(
std::move(created_callback), std::move(created_callback),
base::BindOnce(&StreamFactory::DestroyLoopbackStream, base::BindOnce(&StreamFactory::DestroyLoopbackStream,
base::Unretained(this)), base::Unretained(this)),
audio_manager_->GetWorkerTaskRunner(), std::move(receiver), std::move(task_runner), std::move(receiver), std::move(client),
std::move(client), std::move(observer), params, shared_memory_count, std::move(observer), params, shared_memory_count, &coordinator_,
&coordinator_, group_id); group_id);
loopback_streams_.emplace_back(std::move(stream)); loopback_streams_.emplace_back(std::move(stream));
SetStateForCrashing("created loopback stream"); SetStateForCrashing("created loopback stream");
} }
...@@ -225,7 +253,7 @@ void StreamFactory::DestroyMuter(LocalMuter* muter) { ...@@ -225,7 +253,7 @@ void StreamFactory::DestroyMuter(LocalMuter* muter) {
// Output streams have a task posting before destruction (see the OnError // Output streams have a task posting before destruction (see the OnError
// function in output_stream.cc). To ensure that stream destruction and // function in output_stream.cc). To ensure that stream destruction and
// unmuting is done in the intended order (the order in which the messeges are // unmuting is done in the intended order (the order in which the messages are
// received by the service), we post a task for destroying the muter as well. // received by the service), we post a task for destroying the muter as well.
// Otherwise, a "destroy all streams, then destroy the muter" sequence may // Otherwise, a "destroy all streams, then destroy the muter" sequence may
// result in a brief blip of audio. // result in a brief blip of audio.
...@@ -262,6 +290,12 @@ void StreamFactory::DestroyLoopbackStream(LoopbackStream* stream) { ...@@ -262,6 +290,12 @@ void StreamFactory::DestroyLoopbackStream(LoopbackStream* stream) {
loopback_streams_.erase(it); loopback_streams_.erase(it);
SetStateForCrashing("destroyed loopback stream"); SetStateForCrashing("destroyed loopback stream");
// If all LoopbackStreams have ended, stop and join the worker thread.
if (loopback_streams_.empty()) {
TRACE_EVENT0("audio", "Stop Loopback Worker");
loopback_worker_thread_.Stop();
}
} }
void StreamFactory::SetStateForCrashing(const char* state) { void StreamFactory::SetStateForCrashing(const char* state) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/threading/thread.h"
#include "media/mojo/interfaces/audio_logging.mojom.h" #include "media/mojo/interfaces/audio_logging.mojom.h"
#include "media/mojo/interfaces/audio_output_stream.mojom.h" #include "media/mojo/interfaces/audio_output_stream.mojom.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
...@@ -113,6 +114,7 @@ class StreamFactory final : public mojom::StreamFactory { ...@@ -113,6 +114,7 @@ class StreamFactory final : public mojom::StreamFactory {
// Order of the following members is important for a clean shutdown. // Order of the following members is important for a clean shutdown.
LoopbackCoordinator coordinator_; LoopbackCoordinator coordinator_;
std::vector<std::unique_ptr<LocalMuter>> muters_; std::vector<std::unique_ptr<LocalMuter>> muters_;
base::Thread loopback_worker_thread_;
std::vector<std::unique_ptr<LoopbackStream>> loopback_streams_; std::vector<std::unique_ptr<LoopbackStream>> loopback_streams_;
StreamMonitorCoordinator stream_monitor_coordinator_; StreamMonitorCoordinator stream_monitor_coordinator_;
InputStreamSet input_streams_; InputStreamSet input_streams_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment