Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Unified Diff: media/audio/fake_audio_provider.cc

Issue 922663002: Moved the fake input stream's processing onto the audio worker thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moving browser test updates to a separate patch (this one is big enough) Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/audio/fake_audio_provider.cc
diff --git a/media/audio/fake_audio_input_stream.cc b/media/audio/fake_audio_provider.cc
similarity index 52%
copy from media/audio/fake_audio_input_stream.cc
copy to media/audio/fake_audio_provider.cc
index 4632b258eda2abaf261bb7dba214ab6aba15d8bb..342056a751131d7f4dac6552ccbded42394e0d7e 100644
--- a/media/audio/fake_audio_input_stream.cc
+++ b/media/audio/fake_audio_provider.cc
@@ -1,19 +1,23 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/audio/fake_audio_input_stream.h"
+#include "media/audio/fake_audio_provider.h"
#include "base/bind.h"
-#include "base/command_line.h"
+#include "base/cancelable_callback.h"
#include "base/files/file.h"
+#include "base/files/file_path.h"
#include "base/lazy_instance.h"
-#include "media/audio/audio_manager_base.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "media/audio/audio_parameters.h"
+#include "media/audio/sounds/wav_audio_handler.h"
#include "media/base/audio_bus.h"
-#include "media/base/media_switches.h"
-
-using base::TimeTicks;
-using base::TimeDelta;
+#include "media/base/audio_converter.h"
namespace media {
@@ -102,21 +106,96 @@ static base::LazyInstance<BeepContext> g_beep_context =
} // namespace
-AudioInputStream* FakeAudioInputStream::MakeFakeStream(
- AudioManagerBase* manager,
- const AudioParameters& params) {
- return new FakeAudioInputStream(manager, params);
+class FakeAudioProvider::Worker
+ : public base::RefCountedThreadSafe<FakeAudioProvider::Worker>,
+ public AudioConverter::InputCallback {
+ public:
+ Worker(const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
+ const AudioParameters& params);
+
+ void Open(const base::FilePath& optional_path_to_wav_file);
+ void Start(InputCB input_cb);
+ void Stop();
+ bool IsStopped();
+
+ private:
+ friend class base::RefCountedThreadSafe<Worker>;
+ ~Worker() override;
+
+ void DoCallback();
+ void DoOpen(const base::FilePath& optional_path_to_wav_file);
+ void DoStart();
+ void DoCancel();
+
+ void LoadWavFileIntoWorker(const base::FilePath& wav_filename);
DaleCurtis 2015/02/17 23:27:49 The worker is already a pretty complicated beast.
phoglund_chromium 2015/02/18 10:22:05 All the data needs to live on the worker's thread,
+
+ // Returns true if the device is playing from a file; false if we're beeping.
+ bool PlayingFromFile();
+
+ void PlayFile();
+ void PlayBeep();
+
+ base::Lock input_cb_lock_; // Held while mutating or running |input_cb_|.
+ InputCB input_cb_;
+ base::CancelableClosure input_task_cb_;
+ scoped_ptr<uint8[]> buffer_;
+ int buffer_size_;
+ AudioParameters params_;
+ const scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
+ base::TimeTicks last_callback_time_;
+ base::TimeDelta callback_interval_;
+ base::TimeDelta interval_from_last_beep_;
+ int beep_duration_in_buffers_;
+ int beep_generated_in_buffers_;
+ int beep_period_in_frames_;
+ scoped_ptr<media::AudioBus> audio_bus_;
+ scoped_ptr<uint8[]> wav_file_data_;
+ scoped_ptr<media::WavAudioHandler> wav_audio_handler_;
+ scoped_ptr<media::AudioConverter> file_audio_converter_;
+ int wav_file_read_pos_;
+
+ base::ThreadChecker thread_checker_;
+
+ // If running in file mode, this provides audio data from wav_audio_handler_.
+ double ProvideInput(AudioBus* audio_bus,
+ base::TimeDelta buffer_delay) override;
+};
+
+FakeAudioProvider::FakeAudioProvider(
+ const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
+ const AudioParameters& params)
+ : worker_(new Worker(worker_task_runner, params)) {
+}
+
+FakeAudioProvider::~FakeAudioProvider() {
+ DCHECK(worker_->IsStopped());
}
-FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager,
- const AudioParameters& params)
- : audio_manager_(manager),
- callback_(NULL),
- buffer_size_((params.channels() * params.bits_per_sample() *
+void FakeAudioProvider::OpenInBeepMode() {
+ worker_->Open(base::FilePath());
+}
+
+void FakeAudioProvider::OpenInFileMode(const base::FilePath& path_to_wav_file) {
+ worker_->Open(path_to_wav_file);
+}
+
+void FakeAudioProvider::Start(const InputCB& input_cb) {
+ DCHECK(worker_->IsStopped());
+ worker_->Start(input_cb);
+}
+
+void FakeAudioProvider::Stop() {
+ worker_->Stop();
+}
+
+FakeAudioProvider::Worker::Worker(
+ const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
+ const AudioParameters& params)
+ : buffer_size_((params.channels() * params.bits_per_sample() *
params.frames_per_buffer()) /
8),
params_(params),
- task_runner_(manager->GetTaskRunner()),
+ worker_task_runner_(worker_task_runner),
callback_interval_(base::TimeDelta::FromMilliseconds(
(params.frames_per_buffer() * 1000) / params.sample_rate())),
beep_duration_in_buffers_(kBeepDurationMilliseconds *
@@ -126,70 +205,37 @@ FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager,
beep_generated_in_buffers_(0),
beep_period_in_frames_(params.sample_rate() / kBeepFrequency),
audio_bus_(AudioBus::Create(params)),
- wav_file_read_pos_(0),
- weak_factory_(this) {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ wav_file_read_pos_(0) {
+ // Ensure Start, Stop and Open is called on the same thread (where we're
+ // created doesn't matter though).
+ thread_checker_.DetachFromThread();
}
-FakeAudioInputStream::~FakeAudioInputStream() {}
-
-bool FakeAudioInputStream::Open() {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- buffer_.reset(new uint8[buffer_size_]);
- memset(buffer_.get(), 0, buffer_size_);
- audio_bus_->Zero();
-
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseFileForFakeAudioCapture)) {
- OpenInFileMode(base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
- switches::kUseFileForFakeAudioCapture));
- }
-
- return true;
+FakeAudioProvider::Worker::~Worker() {
+ DCHECK(input_cb_.is_null());
}
-void FakeAudioInputStream::Start(AudioInputCallback* callback) {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- DCHECK(!callback_);
- callback_ = callback;
- last_callback_time_ = TimeTicks::Now();
-
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
- callback_interval_);
+void FakeAudioProvider::Worker::Open(
+ const base::FilePath& optional_path_to_wav_file) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ worker_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Worker::DoOpen, this, optional_path_to_wav_file));
}
-void FakeAudioInputStream::DoCallback() {
- DCHECK(callback_);
-
- const TimeTicks now = TimeTicks::Now();
- base::TimeDelta next_callback_time =
- last_callback_time_ + callback_interval_ * 2 - now;
-
- // If we are falling behind, try to catch up as much as we can in the next
- // callback.
- if (next_callback_time < base::TimeDelta())
- next_callback_time = base::TimeDelta();
-
- if (PlayingFromFile()) {
- PlayFile();
- } else {
- PlayBeep();
- }
-
- last_callback_time_ = now;
+void FakeAudioProvider::Worker::DoOpen(
+ const base::FilePath& optional_path_to_wav_file) {
+ DCHECK(worker_task_runner_->BelongsToCurrentThread());
+ buffer_.reset(new uint8[buffer_size_]);
+ memset(buffer_.get(), 0, buffer_size_);
+ audio_bus_->Zero();
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
- next_callback_time);
+ if (!optional_path_to_wav_file.empty())
+ LoadWavFileIntoWorker(optional_path_to_wav_file);
}
-void FakeAudioInputStream::OpenInFileMode(const base::FilePath& wav_filename) {
- CHECK(!wav_filename.empty())
- << "You must pass the file to use as argument to --"
- << switches::kUseFileForFakeAudioCapture << ".";
+void FakeAudioProvider::Worker::LoadWavFileIntoWorker(
+ const base::FilePath& wav_filename) {
+ DCHECK(worker_task_runner_->BelongsToCurrentThread());
// Read the file, and put its data in a scoped_ptr so it gets deleted later.
size_t file_length = 0;
@@ -212,22 +258,73 @@ void FakeAudioInputStream::OpenInFileMode(const base::FilePath& wav_filename) {
file_audio_converter_->AddInput(this);
}
-bool FakeAudioInputStream::PlayingFromFile() {
+void FakeAudioProvider::Worker::Start(InputCB callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ base::AutoLock scoped_lock(input_cb_lock_);
+ DCHECK(input_cb_.is_null());
+ input_cb_ = callback;
+ }
+ worker_task_runner_->PostTask(FROM_HERE, base::Bind(&Worker::DoStart, this));
+}
+
+void FakeAudioProvider::Worker::DoStart() {
+ DCHECK(worker_task_runner_->BelongsToCurrentThread());
+ DCHECK(buffer_.get() != nullptr) << "Must be opened first.";
+
+ last_callback_time_ = base::TimeTicks::Now();
+
+ input_task_cb_.Reset(base::Bind(&Worker::DoCallback, this));
+ input_task_cb_.callback().Run();
+}
+
+void FakeAudioProvider::Worker::DoCallback() {
+ DCHECK(worker_task_runner_->BelongsToCurrentThread());
+
+ const base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta delay = last_callback_time_ + callback_interval_ * 2 - now;
+
+ // If we are falling behind, try to catch up as much as we can in the next
+ // callback.
+ if (delay < base::TimeDelta())
+ delay = base::TimeDelta();
+
+ if (PlayingFromFile()) {
+ PlayFile();
+ } else {
+ PlayBeep();
+ }
+
+ last_callback_time_ = now;
+ worker_task_runner_->PostDelayedTask(FROM_HERE, input_task_cb_.callback(),
+ delay);
+}
+
+bool FakeAudioProvider::Worker::PlayingFromFile() {
return wav_audio_handler_.get() != nullptr;
}
-void FakeAudioInputStream::PlayFile() {
+void FakeAudioProvider::Worker::PlayFile() {
+ DCHECK(worker_task_runner_->BelongsToCurrentThread());
+
// Stop playing if we've played out the whole file.
if (wav_audio_handler_->AtEnd(wav_file_read_pos_))
return;
file_audio_converter_->Convert(audio_bus_.get());
- callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0);
+ {
+ base::AutoLock scoped_lock(input_cb_lock_);
+ if (input_cb_.is_null())
+ return;
+ input_cb_.Run(audio_bus_.get(), buffer_size_);
+ }
}
-void FakeAudioInputStream::PlayBeep() {
+void FakeAudioProvider::Worker::PlayBeep() {
+ DCHECK(worker_task_runner_->BelongsToCurrentThread());
+
// Accumulate the time from the last beep.
- interval_from_last_beep_ += TimeTicks::Now() - last_callback_time_;
+ interval_from_last_beep_ += base::TimeTicks::Now() - last_callback_time_;
memset(buffer_.get(), 0, buffer_size_);
bool should_beep = false;
@@ -235,7 +332,7 @@ void FakeAudioInputStream::PlayBeep() {
BeepContext* beep_context = g_beep_context.Pointer();
if (beep_context->automatic_beep()) {
base::TimeDelta delta = interval_from_last_beep_ -
- TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs);
+ base::TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs);
if (delta > base::TimeDelta()) {
should_beep = true;
interval_from_last_beep_ = delta;
@@ -272,55 +369,37 @@ void FakeAudioInputStream::PlayBeep() {
audio_bus_->FromInterleaved(
buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8);
- callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0);
-}
-
-void FakeAudioInputStream::Stop() {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- weak_factory_.InvalidateWeakPtrs();
- callback_ = NULL;
-}
-
-void FakeAudioInputStream::Close() {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- audio_manager_->ReleaseInputStream(this);
-}
-
-double FakeAudioInputStream::GetMaxVolume() {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- return 1.0;
-}
-
-void FakeAudioInputStream::SetVolume(double volume) {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
-}
-
-double FakeAudioInputStream::GetVolume() {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- return 1.0;
-}
-
-bool FakeAudioInputStream::IsMuted() {
- DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
- return false;
+ {
+ base::AutoLock scoped_lock(input_cb_lock_);
+ if (input_cb_.is_null())
+ return;
+ input_cb_.Run(audio_bus_.get(), buffer_size_);
+ }
}
-bool FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {
- return false;
+void FakeAudioProvider::Worker::Stop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ base::AutoLock scoped_lock(input_cb_lock_);
+ if (input_cb_.is_null())
+ return;
+ input_cb_.Reset();
+ }
+ worker_task_runner_->PostTask(FROM_HERE, base::Bind(&Worker::DoCancel, this));
}
-bool FakeAudioInputStream::GetAutomaticGainControl() {
- return false;
+bool FakeAudioProvider::Worker::IsStopped() {
+ base::AutoLock scoped_lock(input_cb_lock_);
+ return input_cb_.is_null();
}
-// static
-void FakeAudioInputStream::BeepOnce() {
- BeepContext* beep_context = g_beep_context.Pointer();
- beep_context->SetBeepOnce(true);
+void FakeAudioProvider::Worker::DoCancel() {
+ input_task_cb_.Cancel();
}
-double FakeAudioInputStream::ProvideInput(AudioBus* audio_bus_into_converter,
- base::TimeDelta buffer_delay) {
+double FakeAudioProvider::Worker::ProvideInput(
+ AudioBus* audio_bus_into_converter,
+ base::TimeDelta buffer_delay) {
// Unfilled frames will be zeroed by CopyTo.
size_t bytes_written;
wav_audio_handler_->CopyTo(audio_bus_into_converter, wav_file_read_pos_,
@@ -329,4 +408,9 @@ double FakeAudioInputStream::ProvideInput(AudioBus* audio_bus_into_converter,
return 1.0;
};
+void FakeAudioProvider::BeepOnce() {
+ BeepContext* beep_context = g_beep_context.Pointer();
+ beep_context->SetBeepOnce(true);
+}
+
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698