diff options
author | alokp <alokp@chromium.org> | 2016-03-15 12:34:18 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-15 19:35:46 +0000 |
commit | f4945022d19aaa9a0c70346398f1b2b9e4d64899 (patch) | |
tree | 445ad5112787147f8069f88edb43d3fc51e552f1 | |
parent | fde6c7118d13dbe3e219de55838b514187fffea9 (diff) | |
download | chromium_src-f4945022d19aaa9a0c70346398f1b2b9e4d64899.zip chromium_src-f4945022d19aaa9a0c70346398f1b2b9e4d64899.tar.gz chromium_src-f4945022d19aaa9a0c70346398f1b2b9e4d64899.tar.bz2 |
AudioManagerBase: Create and run the audio thread lazily.
This allows AudioManagerBase subclasses not have to create an
unnecessary thread if they want to use a different audio task runner.
BUG=594234
Review URL: https://codereview.chromium.org/1780333007
Cr-Commit-Position: refs/heads/master@{#381282}
-rw-r--r-- | media/audio/alsa/alsa_output_unittest.cc | 2 | ||||
-rw-r--r-- | media/audio/audio_low_latency_input_output_unittest.cc | 2 | ||||
-rw-r--r-- | media/audio/audio_manager.h | 2 | ||||
-rw-r--r-- | media/audio/audio_manager_base.cc | 63 | ||||
-rw-r--r-- | media/audio/audio_manager_base.h | 9 | ||||
-rw-r--r-- | media/audio/audio_output_proxy_unittest.cc | 3 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.cc | 54 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.h | 5 | ||||
-rw-r--r-- | media/audio/mock_audio_manager.cc | 3 | ||||
-rw-r--r-- | media/audio/mock_audio_manager.h | 2 |
10 files changed, 80 insertions, 65 deletions
diff --git a/media/audio/alsa/alsa_output_unittest.cc b/media/audio/alsa/alsa_output_unittest.cc index 908da6b..1b13863 100644 --- a/media/audio/alsa/alsa_output_unittest.cc +++ b/media/audio/alsa/alsa_output_unittest.cc @@ -95,7 +95,7 @@ class MockAudioManagerAlsa : public AudioManagerAlsa { // We don't mock this method since all tests will do the same thing // and use the current task runner. - scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override { + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override { return base::MessageLoop::current()->task_runner(); } diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc index 9d5f5b1..010b349 100644 --- a/media/audio/audio_low_latency_input_output_unittest.cc +++ b/media/audio/audio_low_latency_input_output_unittest.cc @@ -99,7 +99,7 @@ class MockAudioManager : public AudioManagerAnyPlatform { MockAudioManager() : AudioManagerAnyPlatform(&fake_audio_log_factory_) {} ~MockAudioManager() override {} - scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override { + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override { return base::MessageLoop::current()->task_runner(); } diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index c5b7f194..d3eea4a 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h @@ -178,7 +178,7 @@ class MEDIA_EXPORT AudioManager { const std::string& device_id) = 0; // Returns the task runner used for audio IO. - virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const = 0; + virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() = 0; // Heavyweight tasks should use GetWorkerTaskRunner() instead of // GetTaskRunner(). On most platforms they are the same, but some share the diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 4f7e676..9e88442 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -91,23 +91,7 @@ AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory) // block the UI thread when swapping devices. output_listeners_( base::ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), - audio_thread_("AudioThread"), audio_log_factory_(audio_log_factory) { -#if defined(OS_WIN) - audio_thread_.init_com_with_mta(true); -#elif defined(OS_MACOSX) - // CoreAudio calls must occur on the main thread of the process, which in our - // case is sadly the browser UI thread. Failure to execute calls on the right - // thread leads to crashes and odd behavior. See http://crbug.com/158170. - // TODO(dalecurtis): We should require the message loop to be passed in. - if (base::MessageLoopForUI::IsCurrent()) { - task_runner_ = base::ThreadTaskRunnerHandle::Get(); - return; - } -#endif - - CHECK(audio_thread_.Start()); - task_runner_ = audio_thread_.task_runner(); } AudioManagerBase::~AudioManagerBase() { @@ -116,7 +100,7 @@ AudioManagerBase::~AudioManagerBase() { // stopping the thread, resulting an unexpected behavior. // This way we make sure activities of the audio streams are all stopped // before we destroy them. - CHECK(!audio_thread_.IsRunning()); + CHECK(!audio_thread_); // All the output streams should have been deleted. DCHECK_EQ(0, num_output_streams_); // All the input streams should have been deleted. @@ -127,18 +111,20 @@ base::string16 AudioManagerBase::GetAudioInputDeviceModel() { return base::string16(); } -scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() - const { - return task_runner_; +scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() { + if (!audio_thread_) { + audio_thread_.reset(new base::Thread("AudioThread")); +#if defined(OS_WIN) + audio_thread_->init_com_with_mta(true); +#endif + CHECK(audio_thread_->Start()); + } + return audio_thread_->task_runner(); } scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetWorkerTaskRunner() { - // Lazily start the worker thread. - if (!audio_thread_.IsRunning()) - CHECK(audio_thread_.Start()); - - return audio_thread_.task_runner(); + return GetTaskRunner(); } AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( @@ -146,7 +132,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( const std::string& device_id) { // TODO(miu): Fix ~50 call points across several unit test modules to call // this method on the audio thread, then uncomment the following: - // DCHECK(task_runner_->BelongsToCurrentThread()); + // DCHECK(GetTaskRunner()->BelongsToCurrentThread()); if (!params.IsValid()) { DLOG(ERROR) << "Audio parameters are invalid"; @@ -195,7 +181,7 @@ AudioInputStream* AudioManagerBase::MakeAudioInputStream( const std::string& device_id) { // TODO(miu): Fix ~20 call points across several unit test modules to call // this method on the audio thread, then uncomment the following: - // DCHECK(task_runner_->BelongsToCurrentThread()); + // DCHECK(GetTaskRunner()->BelongsToCurrentThread()); if (!params.IsValid() || (params.channels() > kMaxInputChannels) || device_id.empty()) { @@ -239,7 +225,7 @@ AudioInputStream* AudioManagerBase::MakeAudioInputStream( AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( const AudioParameters& params, const std::string& device_id) { - DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(GetTaskRunner()->BelongsToCurrentThread()); // If the caller supplied an empty device id to select the default device, // we fetch the actual device id of the default device so that the lookup @@ -337,19 +323,24 @@ void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { void AudioManagerBase::Shutdown() { // Only true when we're sharing the UI message loop with the browser. The UI // loop is no longer running at this time and browser destruction is imminent. - if (task_runner_->BelongsToCurrentThread()) { + auto task_runner = GetTaskRunner(); + if (task_runner->BelongsToCurrentThread()) { ShutdownOnAudioThread(); } else { - task_runner_->PostTask(FROM_HERE, base::Bind( - &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); + task_runner->PostTask(FROM_HERE, + base::Bind(&AudioManagerBase::ShutdownOnAudioThread, + base::Unretained(this))); } // Stop() will wait for any posted messages to be processed first. - audio_thread_.Stop(); + if (audio_thread_) { + audio_thread_->Stop(); + audio_thread_.reset(); + } } void AudioManagerBase::ShutdownOnAudioThread() { - DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(GetTaskRunner()->BelongsToCurrentThread()); while (!output_dispatchers_.empty()) { output_dispatchers_.back()->dispatcher->Shutdown(); output_dispatchers_.pop_back(); @@ -358,18 +349,18 @@ void AudioManagerBase::ShutdownOnAudioThread() { void AudioManagerBase::AddOutputDeviceChangeListener( AudioDeviceListener* listener) { - DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(GetTaskRunner()->BelongsToCurrentThread()); output_listeners_.AddObserver(listener); } void AudioManagerBase::RemoveOutputDeviceChangeListener( AudioDeviceListener* listener) { - DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(GetTaskRunner()->BelongsToCurrentThread()); output_listeners_.RemoveObserver(listener); } void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { - DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(GetTaskRunner()->BelongsToCurrentThread()); DVLOG(1) << "Firing OnDeviceChange() notifications."; FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); } diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index bcb6fe3..2a92690 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h @@ -52,7 +52,7 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { ~AudioManagerBase() override; // AudioManager: - scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override; + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override; scoped_refptr<base::SingleThreadTaskRunner> GetWorkerTaskRunner() override; base::string16 GetAudioInputDeviceModel() override; void ShowAudioInputSettings() override; @@ -171,12 +171,7 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { base::ObserverList<AudioDeviceListener> output_listeners_; // Thread used to interact with audio streams created by this audio manager. - base::Thread audio_thread_; - - // The task runner of the audio thread this object runs on. Used for internal - // tasks which run on the audio thread even after Shutdown() has been started - // and GetTaskRunner() starts returning NULL. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_ptr<base::Thread> audio_thread_; // Map of cached AudioOutputDispatcher instances. Must only be touched // from the audio thread (no locking). diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index 019e7b7..f037461 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc @@ -104,8 +104,7 @@ class MockAudioManager : public AudioManagerBase { MOCK_METHOD2(MakeAudioInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); MOCK_METHOD0(ShowAudioInputSettings, void()); - MOCK_CONST_METHOD0(GetTaskRunner, - scoped_refptr<base::SingleThreadTaskRunner>()); + MOCK_METHOD0(GetTaskRunner, scoped_refptr<base::SingleThreadTaskRunner>()); MOCK_METHOD0(GetWorkerTaskRunner, scoped_refptr<base::SingleThreadTaskRunner>()); MOCK_METHOD1(GetAudioInputDeviceNames, void( diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 6eefcf4..78bdb9f 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -370,26 +370,49 @@ AudioManagerMac::AudioManagerMac(AudioLogFactory* audio_log_factory) current_output_device_(kAudioDeviceUnknown) { SetMaxOutputStreamsAllowed(kMaxOutputStreams); + // CoreAudio calls must occur on the main thread of the process, which in our + // case is sadly the browser UI thread. Failure to execute calls on the right + // thread leads to crashes and odd behavior. See http://crbug.com/158170. + // TODO(dalecurtis): We should require the message loop to be passed in. + task_runner_ = base::MessageLoopForUI::IsCurrent() + ? base::ThreadTaskRunnerHandle::Get() + : AudioManagerBase::GetTaskRunner(); + // Task must be posted last to avoid races from handing out "this" to the // audio thread. Always PostTask even if we're on the right thread since // AudioManager creation is on the startup path and this may be slow. - GetTaskRunner()->PostTask(FROM_HERE, base::Bind( - &AudioManagerMac::InitializeOnAudioThread, base::Unretained(this))); + task_runner_->PostTask(FROM_HERE, + base::Bind(&AudioManagerMac::InitializeOnAudioThread, + base::Unretained(this))); } AudioManagerMac::~AudioManagerMac() { - if (GetTaskRunner()->BelongsToCurrentThread()) { + if (task_runner_->BelongsToCurrentThread()) { ShutdownOnAudioThread(); } else { // It's safe to post a task here since Shutdown() will wait for all tasks to // complete before returning. - GetTaskRunner()->PostTask(FROM_HERE, base::Bind( - &AudioManagerMac::ShutdownOnAudioThread, base::Unretained(this))); + task_runner_->PostTask(FROM_HERE, + base::Bind(&AudioManagerMac::ShutdownOnAudioThread, + base::Unretained(this))); } Shutdown(); } +scoped_refptr<base::SingleThreadTaskRunner> AudioManagerMac::GetTaskRunner() { + return task_runner_; +} + +scoped_refptr<base::SingleThreadTaskRunner> +AudioManagerMac::GetWorkerTaskRunner() { + if (!worker_thread_) { + worker_thread_.reset(new base::Thread("AudioWorkerThread")); + CHECK(worker_thread_->Start()); + } + return worker_thread_->task_runner(); +} + bool AudioManagerMac::HasAudioOutputDevices() { return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); } @@ -398,6 +421,7 @@ bool AudioManagerMac::HasAudioInputDevices() { return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); } +// static bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, AudioObjectPropertyScope scope, int* channels) { @@ -441,6 +465,7 @@ bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, return true; } +// static int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); Float64 nominal_sample_rate; @@ -466,6 +491,7 @@ int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { return static_cast<int>(nominal_sample_rate); } +// static int AudioManagerMac::HardwareSampleRate() { // Determine the default output device's sample-rate. AudioDeviceID device_id = kAudioObjectUnknown; @@ -524,7 +550,7 @@ AudioParameters AudioManagerMac::GetInputStreamParameters( std::string AudioManagerMac::GetAssociatedOutputDeviceID( const std::string& input_device_id) { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); if (device == kAudioObjectUnknown) return std::string(); @@ -649,7 +675,7 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( } std::string AudioManagerMac::GetDefaultOutputDeviceID() { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); AudioDeviceID device_id = kAudioObjectUnknown; if (!GetDefaultOutputDevice(&device_id)) return std::string(); @@ -748,12 +774,12 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( } void AudioManagerMac::InitializeOnAudioThread() { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); power_observer_.reset(new AudioPowerObserver()); } void AudioManagerMac::ShutdownOnAudioThread() { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); output_device_listener_.reset(); power_observer_.reset(); @@ -772,7 +798,7 @@ void AudioManagerMac::ShutdownOnAudioThread() { } void AudioManagerMac::HandleDeviceChanges() { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); const int new_sample_rate = HardwareSampleRate(); AudioDeviceID new_output_device; GetDefaultOutputDevice(&new_output_device); @@ -814,17 +840,17 @@ int AudioManagerMac::ChooseBufferSize(bool is_input, int sample_rate) { } bool AudioManagerMac::ShouldDeferStreamStart() const { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); return power_observer_->ShouldDeferStreamStart(); } bool AudioManagerMac::IsOnBatteryPower() const { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); return power_observer_->IsOnBatteryPower(); } size_t AudioManagerMac::GetNumberOfResumeNotifications() const { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); return power_observer_->num_resume_notifications(); } @@ -834,7 +860,7 @@ bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, size_t desired_buffer_size, bool* size_was_changed, size_t* io_buffer_frame_size) { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(task_runner_->BelongsToCurrentThread()); const bool is_input = (element == 1); DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index 2112a88..0545f43 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -29,6 +29,8 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { AudioManagerMac(AudioLogFactory* audio_log_factory); // Implementation of AudioManager. + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override; + scoped_refptr<base::SingleThreadTaskRunner> GetWorkerTaskRunner() override; bool HasAudioOutputDevices() override; bool HasAudioInputDevices() override; void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override; @@ -122,6 +124,9 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { scoped_ptr<AudioDeviceListenerMac> output_device_listener_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_ptr<base::Thread> worker_thread_; + // Track the output sample-rate and the default output device // so we can intelligently handle device notifications only when necessary. int current_sample_rate_; diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc index e8aacbe..7183405 100644 --- a/media/audio/mock_audio_manager.cc +++ b/media/audio/mock_audio_manager.cc @@ -63,8 +63,7 @@ media::AudioInputStream* MockAudioManager::MakeAudioInputStream( return NULL; } -scoped_refptr<base::SingleThreadTaskRunner> MockAudioManager::GetTaskRunner() - const { +scoped_refptr<base::SingleThreadTaskRunner> MockAudioManager::GetTaskRunner() { return task_runner_; } diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h index 536ff6a..60a8b1e 100644 --- a/media/audio/mock_audio_manager.h +++ b/media/audio/mock_audio_manager.h @@ -50,7 +50,7 @@ class MockAudioManager : public media::AudioManager { const media::AudioParameters& params, const std::string& device_id) override; - scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override; + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override; scoped_refptr<base::SingleThreadTaskRunner> GetWorkerTaskRunner() override; void AddOutputDeviceChangeListener(AudioDeviceListener* listener) override; |