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

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

Issue 148373004: Abort expensive AudioManager methods once shutdown starts. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Atomics. Created 6 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 | Annotate | Revision Log
« no previous file with comments | « media/audio/audio_manager_base.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory) 74 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
75 : max_num_output_streams_(kDefaultMaxOutputStreams), 75 : max_num_output_streams_(kDefaultMaxOutputStreams),
76 max_num_input_streams_(kDefaultMaxInputStreams), 76 max_num_input_streams_(kDefaultMaxInputStreams),
77 num_output_streams_(0), 77 num_output_streams_(0),
78 num_input_streams_(0), 78 num_input_streams_(0),
79 // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't 79 // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't
80 // block the UI thread when swapping devices. 80 // block the UI thread when swapping devices.
81 output_listeners_( 81 output_listeners_(
82 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), 82 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
83 audio_thread_("AudioThread"), 83 audio_thread_("AudioThread"),
84 audio_log_factory_(audio_log_factory) { 84 audio_log_factory_(audio_log_factory),
85 in_shutdown_(0) {
85 #if defined(OS_WIN) 86 #if defined(OS_WIN)
86 audio_thread_.init_com_with_mta(true); 87 audio_thread_.init_com_with_mta(true);
87 #elif defined(OS_MACOSX) 88 #elif defined(OS_MACOSX)
88 // CoreAudio calls must occur on the main thread of the process, which in our 89 // CoreAudio calls must occur on the main thread of the process, which in our
89 // case is sadly the browser UI thread. Failure to execute calls on the right 90 // case is sadly the browser UI thread. Failure to execute calls on the right
90 // thread leads to crashes and odd behavior. See http://crbug.com/158170. 91 // thread leads to crashes and odd behavior. See http://crbug.com/158170.
91 // TODO(dalecurtis): We should require the message loop to be passed in. 92 // TODO(dalecurtis): We should require the message loop to be passed in.
92 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 93 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
93 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) && 94 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) &&
94 base::MessageLoopProxy::current().get() && 95 base::MessageLoopProxy::current().get() &&
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 132
132 return audio_thread_.message_loop_proxy(); 133 return audio_thread_.message_loop_proxy();
133 } 134 }
134 135
135 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( 136 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
136 const AudioParameters& params, 137 const AudioParameters& params,
137 const std::string& device_id) { 138 const std::string& device_id) {
138 // TODO(miu): Fix ~50 call points across several unit test modules to call 139 // TODO(miu): Fix ~50 call points across several unit test modules to call
139 // this method on the audio thread, then uncomment the following: 140 // this method on the audio thread, then uncomment the following:
140 // DCHECK(task_runner_->BelongsToCurrentThread()); 141 // DCHECK(task_runner_->BelongsToCurrentThread());
142 if (base::AtomicRefCountIsOne(&in_shutdown_))
143 return NULL;
141 144
142 if (!params.IsValid()) { 145 if (!params.IsValid()) {
143 DLOG(ERROR) << "Audio parameters are invalid"; 146 DLOG(ERROR) << "Audio parameters are invalid";
144 return NULL; 147 return NULL;
145 } 148 }
146 149
147 // Limit the number of audio streams opened. This is to prevent using 150 // Limit the number of audio streams opened. This is to prevent using
148 // excessive resources for a large number of audio streams. More 151 // excessive resources for a large number of audio streams. More
149 // importantly it prevents instability on certain systems. 152 // importantly it prevents instability on certain systems.
150 // See bug: http://crbug.com/30242. 153 // See bug: http://crbug.com/30242.
(...skipping 29 matching lines...) Expand all
180 183
181 return stream; 184 return stream;
182 } 185 }
183 186
184 AudioInputStream* AudioManagerBase::MakeAudioInputStream( 187 AudioInputStream* AudioManagerBase::MakeAudioInputStream(
185 const AudioParameters& params, 188 const AudioParameters& params,
186 const std::string& device_id) { 189 const std::string& device_id) {
187 // TODO(miu): Fix ~20 call points across several unit test modules to call 190 // TODO(miu): Fix ~20 call points across several unit test modules to call
188 // this method on the audio thread, then uncomment the following: 191 // this method on the audio thread, then uncomment the following:
189 // DCHECK(task_runner_->BelongsToCurrentThread()); 192 // DCHECK(task_runner_->BelongsToCurrentThread());
193 if (base::AtomicRefCountIsOne(&in_shutdown_))
194 return NULL;
190 195
191 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || 196 if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
192 device_id.empty()) { 197 device_id.empty()) {
193 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; 198 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
194 return NULL; 199 return NULL;
195 } 200 }
196 201
197 if (num_input_streams_ >= max_num_input_streams_) { 202 if (num_input_streams_ >= max_num_input_streams_) {
198 DLOG(ERROR) << "Number of opened input audio streams " 203 DLOG(ERROR) << "Number of opened input audio streams "
199 << num_input_streams_ 204 << num_input_streams_
(...skipping 21 matching lines...) Expand all
221 ++num_input_streams_; 226 ++num_input_streams_;
222 } 227 }
223 228
224 return stream; 229 return stream;
225 } 230 }
226 231
227 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( 232 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
228 const AudioParameters& params, 233 const AudioParameters& params,
229 const std::string& device_id) { 234 const std::string& device_id) {
230 DCHECK(task_runner_->BelongsToCurrentThread()); 235 DCHECK(task_runner_->BelongsToCurrentThread());
236 if (base::AtomicRefCountIsOne(&in_shutdown_))
237 return NULL;
231 238
232 // If the caller supplied an empty device id to select the default device, 239 // If the caller supplied an empty device id to select the default device,
233 // we fetch the actual device id of the default device so that the lookup 240 // we fetch the actual device id of the default device so that the lookup
234 // will find the correct device regardless of whether it was opened as 241 // will find the correct device regardless of whether it was opened as
235 // "default" or via the specific id. 242 // "default" or via the specific id.
236 // NOTE: Implementations that don't yet support opening non-default output 243 // NOTE: Implementations that don't yet support opening non-default output
237 // devices may return an empty string from GetDefaultOutputDeviceID(). 244 // devices may return an empty string from GetDefaultOutputDeviceID().
238 std::string output_device_id = device_id.empty() ? 245 std::string output_device_id = device_id.empty() ?
239 GetDefaultOutputDeviceID() : device_id; 246 GetDefaultOutputDeviceID() : device_id;
240 247
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 } 322 }
316 323
317 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { 324 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
318 DCHECK(stream); 325 DCHECK(stream);
319 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. 326 // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
320 --num_input_streams_; 327 --num_input_streams_;
321 delete stream; 328 delete stream;
322 } 329 }
323 330
324 void AudioManagerBase::Shutdown() { 331 void AudioManagerBase::Shutdown() {
332 DCHECK(base::AtomicRefCountIsZero(&in_shutdown_));
333 base::AtomicRefCountInc(&in_shutdown_);
334
325 // Only true when we're sharing the UI message loop with the browser. The UI 335 // Only true when we're sharing the UI message loop with the browser. The UI
326 // loop is no longer running at this time and browser destruction is imminent. 336 // loop is no longer running at this time and browser destruction is imminent.
327 if (task_runner_->BelongsToCurrentThread()) { 337 if (task_runner_->BelongsToCurrentThread()) {
328 ShutdownOnAudioThread(); 338 ShutdownOnAudioThread();
329 } else { 339 } else {
330 task_runner_->PostTask(FROM_HERE, base::Bind( 340 task_runner_->PostTask(FROM_HERE, base::Bind(
331 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); 341 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
332 } 342 }
333 343
334 // Stop() will wait for any posted messages to be processed first. 344 // Stop() will wait for any posted messages to be processed first.
335 audio_thread_.Stop(); 345 audio_thread_.Stop();
336 } 346 }
337 347
338 void AudioManagerBase::ShutdownOnAudioThread() { 348 void AudioManagerBase::ShutdownOnAudioThread() {
339 DCHECK(task_runner_->BelongsToCurrentThread()); 349 DCHECK(task_runner_->BelongsToCurrentThread());
350 DCHECK(base::AtomicRefCountIsOne(&in_shutdown_));
340 351
341 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 352 AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
342 for (; it != output_dispatchers_.end(); ++it) { 353 for (; it != output_dispatchers_.end(); ++it) {
343 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; 354 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher;
344 dispatcher->Shutdown(); 355 dispatcher->Shutdown();
345 356
346 // All AudioOutputProxies must have been freed before Shutdown is called. 357 // All AudioOutputProxies must have been freed before Shutdown is called.
347 // If they still exist, things will go bad. They have direct pointers to 358 // If they still exist, things will go bad. They have direct pointers to
348 // both physical audio stream objects that belong to the dispatcher as 359 // both physical audio stream objects that belong to the dispatcher as
349 // well as the message loop of the audio thread that will soon go away. 360 // well as the message loop of the audio thread that will soon go away.
(...skipping 12 matching lines...) Expand all
362 } 373 }
363 374
364 void AudioManagerBase::RemoveOutputDeviceChangeListener( 375 void AudioManagerBase::RemoveOutputDeviceChangeListener(
365 AudioDeviceListener* listener) { 376 AudioDeviceListener* listener) {
366 DCHECK(task_runner_->BelongsToCurrentThread()); 377 DCHECK(task_runner_->BelongsToCurrentThread());
367 output_listeners_.RemoveObserver(listener); 378 output_listeners_.RemoveObserver(listener);
368 } 379 }
369 380
370 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { 381 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
371 DCHECK(task_runner_->BelongsToCurrentThread()); 382 DCHECK(task_runner_->BelongsToCurrentThread());
383 if (base::AtomicRefCountIsOne(&in_shutdown_))
384 return;
372 DVLOG(1) << "Firing OnDeviceChange() notifications."; 385 DVLOG(1) << "Firing OnDeviceChange() notifications.";
373 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); 386 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
374 } 387 }
375 388
376 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { 389 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
377 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), 390 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
378 AudioParameters()); 391 AudioParameters());
379 } 392 }
380 393
381 AudioParameters AudioManagerBase::GetOutputStreamParameters( 394 AudioParameters AudioManagerBase::GetOutputStreamParameters(
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 (*it)->dispatcher->CloseStreamsForWedgeFix(); 450 (*it)->dispatcher->CloseStreamsForWedgeFix();
438 } 451 }
439 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 452 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
440 it != output_dispatchers_.end(); ++it) { 453 it != output_dispatchers_.end(); ++it) {
441 (*it)->dispatcher->RestartStreamsForWedgeFix(); 454 (*it)->dispatcher->RestartStreamsForWedgeFix();
442 } 455 }
443 #endif 456 #endif
444 } 457 }
445 458
446 } // namespace media 459 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_manager_base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698