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

Side by Side Diff: media/audio/audio_manager_base.cc

Issue 1780333007: AudioManagerBase: Create and run the audio thread lazily. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Created 4 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_manager_base.h" 5 #include "media/audio/audio_manager_base.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory) 84 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
85 : max_num_output_streams_(kDefaultMaxOutputStreams), 85 : max_num_output_streams_(kDefaultMaxOutputStreams),
86 max_num_input_streams_(kDefaultMaxInputStreams), 86 max_num_input_streams_(kDefaultMaxInputStreams),
87 num_output_streams_(0), 87 num_output_streams_(0),
88 num_input_streams_(0), 88 num_input_streams_(0),
89 // TODO(dalecurtis): Switch this to an base::ObserverListThreadSafe, so we 89 // TODO(dalecurtis): Switch this to an base::ObserverListThreadSafe, so we
90 // don't 90 // don't
91 // block the UI thread when swapping devices. 91 // block the UI thread when swapping devices.
92 output_listeners_( 92 output_listeners_(
93 base::ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), 93 base::ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
94 audio_thread_("AudioThread"),
95 audio_log_factory_(audio_log_factory) { 94 audio_log_factory_(audio_log_factory) {
96 #if defined(OS_WIN)
97 audio_thread_.init_com_with_mta(true);
98 #elif defined(OS_MACOSX)
99 // CoreAudio calls must occur on the main thread of the process, which in our
100 // case is sadly the browser UI thread. Failure to execute calls on the right
101 // thread leads to crashes and odd behavior. See http://crbug.com/158170.
102 // TODO(dalecurtis): We should require the message loop to be passed in.
103 if (base::MessageLoopForUI::IsCurrent()) {
104 task_runner_ = base::ThreadTaskRunnerHandle::Get();
105 return;
106 }
107 #endif
108
109 CHECK(audio_thread_.Start());
110 task_runner_ = audio_thread_.task_runner();
111 } 95 }
112 96
113 AudioManagerBase::~AudioManagerBase() { 97 AudioManagerBase::~AudioManagerBase() {
114 // The platform specific AudioManager implementation must have already 98 // The platform specific AudioManager implementation must have already
115 // stopped the audio thread. Otherwise, we may destroy audio streams before 99 // stopped the audio thread. Otherwise, we may destroy audio streams before
116 // stopping the thread, resulting an unexpected behavior. 100 // stopping the thread, resulting an unexpected behavior.
117 // This way we make sure activities of the audio streams are all stopped 101 // This way we make sure activities of the audio streams are all stopped
118 // before we destroy them. 102 // before we destroy them.
119 CHECK(!audio_thread_.IsRunning()); 103 CHECK(!audio_thread_);
120 // All the output streams should have been deleted. 104 // All the output streams should have been deleted.
121 DCHECK_EQ(0, num_output_streams_); 105 DCHECK_EQ(0, num_output_streams_);
122 // All the input streams should have been deleted. 106 // All the input streams should have been deleted.
123 DCHECK_EQ(0, num_input_streams_); 107 DCHECK_EQ(0, num_input_streams_);
124 } 108 }
125 109
126 base::string16 AudioManagerBase::GetAudioInputDeviceModel() { 110 base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
127 return base::string16(); 111 return base::string16();
128 } 112 }
129 113
130 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() 114 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
131 const { 115 if (!audio_thread_) {
132 return task_runner_; 116 audio_thread_.reset(new base::Thread("AudioThread"));
117 #if defined(OS_WIN)
118 audio_thread_->init_com_with_mta(true);
119 #endif
120 CHECK(audio_thread_->Start());
121 }
122 return audio_thread_->task_runner();
133 } 123 }
134 124
135 scoped_refptr<base::SingleThreadTaskRunner> 125 scoped_refptr<base::SingleThreadTaskRunner>
136 AudioManagerBase::GetWorkerTaskRunner() { 126 AudioManagerBase::GetWorkerTaskRunner() {
137 // Lazily start the worker thread. 127 return GetTaskRunner();
138 if (!audio_thread_.IsRunning())
139 CHECK(audio_thread_.Start());
140
141 return audio_thread_.task_runner();
142 } 128 }
143 129
144 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( 130 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
145 const AudioParameters& params, 131 const AudioParameters& params,
146 const std::string& device_id) { 132 const std::string& device_id) {
147 // TODO(miu): Fix ~50 call points across several unit test modules to call 133 // TODO(miu): Fix ~50 call points across several unit test modules to call
148 // this method on the audio thread, then uncomment the following: 134 // this method on the audio thread, then uncomment the following:
149 // DCHECK(task_runner_->BelongsToCurrentThread()); 135 // DCHECK(GetTaskRunner()->BelongsToCurrentThread());
150 136
151 if (!params.IsValid()) { 137 if (!params.IsValid()) {
152 DLOG(ERROR) << "Audio parameters are invalid"; 138 DLOG(ERROR) << "Audio parameters are invalid";
153 return NULL; 139 return NULL;
154 } 140 }
155 141
156 // Limit the number of audio streams opened. This is to prevent using 142 // Limit the number of audio streams opened. This is to prevent using
157 // excessive resources for a large number of audio streams. More 143 // excessive resources for a large number of audio streams. More
158 // importantly it prevents instability on certain systems. 144 // importantly it prevents instability on certain systems.
159 // See bug: http://crbug.com/30242. 145 // See bug: http://crbug.com/30242.
(...skipping 28 matching lines...) Expand all
188 } 174 }
189 175
190 return stream; 176 return stream;
191 } 177 }
192 178
193 AudioInputStream* AudioManagerBase::MakeAudioInputStream( 179 AudioInputStream* AudioManagerBase::MakeAudioInputStream(
194 const AudioParameters& params, 180 const AudioParameters& params,
195 const std::string& device_id) { 181 const std::string& device_id) {
196 // TODO(miu): Fix ~20 call points across several unit test modules to call 182 // TODO(miu): Fix ~20 call points across several unit test modules to call
197 // this method on the audio thread, then uncomment the following: 183 // this method on the audio thread, then uncomment the following:
198 // DCHECK(task_runner_->BelongsToCurrentThread()); 184 // DCHECK(GetTaskRunner()->BelongsToCurrentThread());
199 185
200 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || 186 if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
201 device_id.empty()) { 187 device_id.empty()) {
202 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; 188 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
203 return NULL; 189 return NULL;
204 } 190 }
205 191
206 if (num_input_streams_ >= max_num_input_streams_) { 192 if (num_input_streams_ >= max_num_input_streams_) {
207 DLOG(ERROR) << "Number of opened input audio streams " 193 DLOG(ERROR) << "Number of opened input audio streams "
208 << num_input_streams_ 194 << num_input_streams_
(...skipping 23 matching lines...) Expand all
232 if (stream) { 218 if (stream) {
233 ++num_input_streams_; 219 ++num_input_streams_;
234 } 220 }
235 221
236 return stream; 222 return stream;
237 } 223 }
238 224
239 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( 225 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
240 const AudioParameters& params, 226 const AudioParameters& params,
241 const std::string& device_id) { 227 const std::string& device_id) {
242 DCHECK(task_runner_->BelongsToCurrentThread()); 228 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
243 229
244 // If the caller supplied an empty device id to select the default device, 230 // If the caller supplied an empty device id to select the default device,
245 // we fetch the actual device id of the default device so that the lookup 231 // we fetch the actual device id of the default device so that the lookup
246 // will find the correct device regardless of whether it was opened as 232 // will find the correct device regardless of whether it was opened as
247 // "default" or via the specific id. 233 // "default" or via the specific id.
248 // NOTE: Implementations that don't yet support opening non-default output 234 // NOTE: Implementations that don't yet support opening non-default output
249 // devices may return an empty string from GetDefaultOutputDeviceID(). 235 // devices may return an empty string from GetDefaultOutputDeviceID().
250 std::string output_device_id = 236 std::string output_device_id =
251 IsDefaultDeviceId(device_id) ? GetDefaultOutputDeviceID() : device_id; 237 IsDefaultDeviceId(device_id) ? GetDefaultOutputDeviceID() : device_id;
252 238
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { 316 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
331 DCHECK(stream); 317 DCHECK(stream);
332 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. 318 // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
333 --num_input_streams_; 319 --num_input_streams_;
334 delete stream; 320 delete stream;
335 } 321 }
336 322
337 void AudioManagerBase::Shutdown() { 323 void AudioManagerBase::Shutdown() {
338 // Only true when we're sharing the UI message loop with the browser. The UI 324 // Only true when we're sharing the UI message loop with the browser. The UI
339 // loop is no longer running at this time and browser destruction is imminent. 325 // loop is no longer running at this time and browser destruction is imminent.
340 if (task_runner_->BelongsToCurrentThread()) { 326 auto task_runner = GetTaskRunner();
327 if (task_runner->BelongsToCurrentThread()) {
341 ShutdownOnAudioThread(); 328 ShutdownOnAudioThread();
342 } else { 329 } else {
343 task_runner_->PostTask(FROM_HERE, base::Bind( 330 task_runner->PostTask(FROM_HERE,
344 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); 331 base::Bind(&AudioManagerBase::ShutdownOnAudioThread,
332 base::Unretained(this)));
345 } 333 }
346 334
347 // Stop() will wait for any posted messages to be processed first. 335 // Destryoing the audio thread will stop it if necessary, which in turn
348 audio_thread_.Stop(); 336 // will wait for any posted messages to be processed first.
337 audio_thread_.reset();
349 } 338 }
350 339
351 void AudioManagerBase::ShutdownOnAudioThread() { 340 void AudioManagerBase::ShutdownOnAudioThread() {
352 DCHECK(task_runner_->BelongsToCurrentThread()); 341 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
353 while (!output_dispatchers_.empty()) { 342 while (!output_dispatchers_.empty()) {
354 output_dispatchers_.back()->dispatcher->Shutdown(); 343 output_dispatchers_.back()->dispatcher->Shutdown();
355 output_dispatchers_.pop_back(); 344 output_dispatchers_.pop_back();
356 } 345 }
357 } 346 }
358 347
359 void AudioManagerBase::AddOutputDeviceChangeListener( 348 void AudioManagerBase::AddOutputDeviceChangeListener(
360 AudioDeviceListener* listener) { 349 AudioDeviceListener* listener) {
361 DCHECK(task_runner_->BelongsToCurrentThread()); 350 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
362 output_listeners_.AddObserver(listener); 351 output_listeners_.AddObserver(listener);
363 } 352 }
364 353
365 void AudioManagerBase::RemoveOutputDeviceChangeListener( 354 void AudioManagerBase::RemoveOutputDeviceChangeListener(
366 AudioDeviceListener* listener) { 355 AudioDeviceListener* listener) {
367 DCHECK(task_runner_->BelongsToCurrentThread()); 356 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
368 output_listeners_.RemoveObserver(listener); 357 output_listeners_.RemoveObserver(listener);
369 } 358 }
370 359
371 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { 360 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
372 DCHECK(task_runner_->BelongsToCurrentThread()); 361 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
373 DVLOG(1) << "Firing OnDeviceChange() notifications."; 362 DVLOG(1) << "Firing OnDeviceChange() notifications.";
374 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); 363 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
375 } 364 }
376 365
377 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { 366 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
378 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), 367 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
379 AudioParameters()); 368 AudioParameters());
380 } 369 }
381 370
382 AudioParameters AudioManagerBase::GetOutputStreamParameters( 371 AudioParameters AudioManagerBase::GetOutputStreamParameters(
(...skipping 27 matching lines...) Expand all
410 399
411 return 0; 400 return 0;
412 } 401 }
413 402
414 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog( 403 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
415 AudioLogFactory::AudioComponent component) { 404 AudioLogFactory::AudioComponent component) {
416 return audio_log_factory_->CreateAudioLog(component); 405 return audio_log_factory_->CreateAudioLog(component);
417 } 406 }
418 407
419 } // namespace media 408 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698