| Index: media/audio/audio_manager_base.cc
|
| diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc
|
| index 8845585f6a468ae781e0f8fa1cb837bccd91be74..8a6acc2e7bc89afafedffcb1e857f3c653063028 100644
|
| --- a/media/audio/audio_manager_base.cc
|
| +++ b/media/audio/audio_manager_base.cc
|
| @@ -89,12 +89,8 @@
|
| return session_id && device_id.empty();
|
| }
|
|
|
| -AudioManagerBase::AudioManagerBase(
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
| - scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
|
| - AudioLogFactory* audio_log_factory)
|
| - : AudioManager(std::move(task_runner), std::move(worker_task_runner)),
|
| - max_num_output_streams_(kDefaultMaxOutputStreams),
|
| +AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
|
| + : max_num_output_streams_(kDefaultMaxOutputStreams),
|
| max_num_input_streams_(kDefaultMaxInputStreams),
|
| num_output_streams_(0),
|
| num_input_streams_(0),
|
| @@ -103,19 +99,40 @@
|
| // block the UI thread when swapping devices.
|
| output_listeners_(
|
| base::ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
|
| - audio_log_factory_(audio_log_factory) {}
|
| + audio_log_factory_(audio_log_factory) {
|
| +}
|
|
|
| AudioManagerBase::~AudioManagerBase() {
|
| - DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| -
|
| + // The platform specific AudioManager implementation must have already
|
| + // stopped the audio thread. Otherwise, we may destroy audio streams before
|
| + // 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_);
|
| // All the output streams should have been deleted.
|
| - CHECK_EQ(0, num_output_streams_);
|
| + DCHECK_EQ(0, num_output_streams_);
|
| // All the input streams should have been deleted.
|
| - CHECK_EQ(0, num_input_streams_);
|
| + DCHECK_EQ(0, num_input_streams_);
|
| }
|
|
|
| base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
|
| return base::string16();
|
| +}
|
| +
|
| +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() {
|
| + return GetTaskRunner();
|
| }
|
|
|
| AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
|
| @@ -312,8 +329,26 @@
|
| }
|
|
|
| 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.
|
| + auto task_runner = GetTaskRunner();
|
| + if (task_runner->BelongsToCurrentThread()) {
|
| + ShutdownOnAudioThread();
|
| + } else {
|
| + task_runner->PostTask(FROM_HERE,
|
| + base::Bind(&AudioManagerBase::ShutdownOnAudioThread,
|
| + base::Unretained(this)));
|
| + }
|
| +
|
| + // Stop() will wait for any posted messages to be processed first.
|
| + if (audio_thread_) {
|
| + audio_thread_->Stop();
|
| + audio_thread_.reset();
|
| + }
|
| +}
|
| +
|
| +void AudioManagerBase::ShutdownOnAudioThread() {
|
| DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| - // Close all output streams.
|
| while (!output_dispatchers_.empty()) {
|
| output_dispatchers_.back()->dispatcher->Shutdown();
|
| output_dispatchers_.pop_back();
|
|
|