| OLD | NEW |
| 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/message_loop/message_loop_proxy.h" | |
| 11 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| 12 #include "build/build_config.h" | 11 #include "build/build_config.h" |
| 13 #include "media/audio/audio_output_dispatcher_impl.h" | 12 #include "media/audio/audio_output_dispatcher_impl.h" |
| 14 #include "media/audio/audio_output_proxy.h" | 13 #include "media/audio/audio_output_proxy.h" |
| 15 #include "media/audio/audio_output_resampler.h" | 14 #include "media/audio/audio_output_resampler.h" |
| 16 #include "media/audio/fake_audio_input_stream.h" | 15 #include "media/audio/fake_audio_input_stream.h" |
| 17 #include "media/audio/fake_audio_output_stream.h" | 16 #include "media/audio/fake_audio_output_stream.h" |
| 18 #include "media/base/media_switches.h" | 17 #include "media/base/media_switches.h" |
| 19 | 18 |
| 20 namespace media { | 19 namespace media { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 audio_thread_.init_com_with_mta(true); | 91 audio_thread_.init_com_with_mta(true); |
| 93 #elif defined(OS_MACOSX) | 92 #elif defined(OS_MACOSX) |
| 94 // CoreAudio calls must occur on the main thread of the process, which in our | 93 // CoreAudio calls must occur on the main thread of the process, which in our |
| 95 // case is sadly the browser UI thread. Failure to execute calls on the right | 94 // case is sadly the browser UI thread. Failure to execute calls on the right |
| 96 // thread leads to crashes and odd behavior. See http://crbug.com/158170. | 95 // thread leads to crashes and odd behavior. See http://crbug.com/158170. |
| 97 // TODO(dalecurtis): We should require the message loop to be passed in. | 96 // TODO(dalecurtis): We should require the message loop to be passed in. |
| 98 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 97 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 99 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) && | 98 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) && |
| 100 base::MessageLoopProxy::current().get() && | 99 base::MessageLoopProxy::current().get() && |
| 101 base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_UI)) { | 100 base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_UI)) { |
| 102 message_loop_ = base::MessageLoopProxy::current(); | 101 task_runner_ = base::MessageLoopProxy::current(); |
| 103 return; | 102 return; |
| 104 } | 103 } |
| 105 #endif | 104 #endif |
| 106 | 105 |
| 107 CHECK(audio_thread_.Start()); | 106 CHECK(audio_thread_.Start()); |
| 108 message_loop_ = audio_thread_.message_loop_proxy(); | 107 task_runner_ = audio_thread_.message_loop_proxy(); |
| 109 } | 108 } |
| 110 | 109 |
| 111 AudioManagerBase::~AudioManagerBase() { | 110 AudioManagerBase::~AudioManagerBase() { |
| 112 // The platform specific AudioManager implementation must have already | 111 // The platform specific AudioManager implementation must have already |
| 113 // stopped the audio thread. Otherwise, we may destroy audio streams before | 112 // stopped the audio thread. Otherwise, we may destroy audio streams before |
| 114 // stopping the thread, resulting an unexpected behavior. | 113 // stopping the thread, resulting an unexpected behavior. |
| 115 // This way we make sure activities of the audio streams are all stopped | 114 // This way we make sure activities of the audio streams are all stopped |
| 116 // before we destroy them. | 115 // before we destroy them. |
| 117 CHECK(!audio_thread_.IsRunning()); | 116 CHECK(!audio_thread_.IsRunning()); |
| 118 // All the output streams should have been deleted. | 117 // All the output streams should have been deleted. |
| 119 DCHECK_EQ(0, num_output_streams_); | 118 DCHECK_EQ(0, num_output_streams_); |
| 120 // All the input streams should have been deleted. | 119 // All the input streams should have been deleted. |
| 121 DCHECK_EQ(0, num_input_streams_); | 120 DCHECK_EQ(0, num_input_streams_); |
| 122 } | 121 } |
| 123 | 122 |
| 124 base::string16 AudioManagerBase::GetAudioInputDeviceModel() { | 123 base::string16 AudioManagerBase::GetAudioInputDeviceModel() { |
| 125 return base::string16(); | 124 return base::string16(); |
| 126 } | 125 } |
| 127 | 126 |
| 128 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { | 127 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() { |
| 129 return message_loop_; | 128 return task_runner_; |
| 130 } | 129 } |
| 131 | 130 |
| 132 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() { | 131 scoped_refptr<base::SingleThreadTaskRunner> |
| 132 AudioManagerBase::GetWorkerTaskRunner() { |
| 133 // Lazily start the worker thread. | 133 // Lazily start the worker thread. |
| 134 if (!audio_thread_.IsRunning()) | 134 if (!audio_thread_.IsRunning()) |
| 135 CHECK(audio_thread_.Start()); | 135 CHECK(audio_thread_.Start()); |
| 136 | 136 |
| 137 return audio_thread_.message_loop_proxy(); | 137 return audio_thread_.message_loop_proxy(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( | 140 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( |
| 141 const AudioParameters& params, | 141 const AudioParameters& params, |
| 142 const std::string& device_id, | 142 const std::string& device_id, |
| 143 const std::string& input_device_id) { | 143 const std::string& input_device_id) { |
| 144 // TODO(miu): Fix ~50 call points across several unit test modules to call | 144 // TODO(miu): Fix ~50 call points across several unit test modules to call |
| 145 // this method on the audio thread, then uncomment the following: | 145 // this method on the audio thread, then uncomment the following: |
| 146 // DCHECK(message_loop_->BelongsToCurrentThread()); | 146 // DCHECK(task_runner_->BelongsToCurrentThread()); |
| 147 | 147 |
| 148 if (!params.IsValid()) { | 148 if (!params.IsValid()) { |
| 149 DLOG(ERROR) << "Audio parameters are invalid"; | 149 DLOG(ERROR) << "Audio parameters are invalid"; |
| 150 return NULL; | 150 return NULL; |
| 151 } | 151 } |
| 152 | 152 |
| 153 // Limit the number of audio streams opened. This is to prevent using | 153 // Limit the number of audio streams opened. This is to prevent using |
| 154 // excessive resources for a large number of audio streams. More | 154 // excessive resources for a large number of audio streams. More |
| 155 // importantly it prevents instability on certain systems. | 155 // importantly it prevents instability on certain systems. |
| 156 // See bug: http://crbug.com/30242. | 156 // See bug: http://crbug.com/30242. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 185 } | 185 } |
| 186 | 186 |
| 187 return stream; | 187 return stream; |
| 188 } | 188 } |
| 189 | 189 |
| 190 AudioInputStream* AudioManagerBase::MakeAudioInputStream( | 190 AudioInputStream* AudioManagerBase::MakeAudioInputStream( |
| 191 const AudioParameters& params, | 191 const AudioParameters& params, |
| 192 const std::string& device_id) { | 192 const std::string& device_id) { |
| 193 // TODO(miu): Fix ~20 call points across several unit test modules to call | 193 // TODO(miu): Fix ~20 call points across several unit test modules to call |
| 194 // this method on the audio thread, then uncomment the following: | 194 // this method on the audio thread, then uncomment the following: |
| 195 // DCHECK(message_loop_->BelongsToCurrentThread()); | 195 // DCHECK(task_runner_->BelongsToCurrentThread()); |
| 196 | 196 |
| 197 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || | 197 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || |
| 198 device_id.empty()) { | 198 device_id.empty()) { |
| 199 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; | 199 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; |
| 200 return NULL; | 200 return NULL; |
| 201 } | 201 } |
| 202 | 202 |
| 203 if (num_input_streams_ >= max_num_input_streams_) { | 203 if (num_input_streams_ >= max_num_input_streams_) { |
| 204 DLOG(ERROR) << "Number of opened input audio streams " | 204 DLOG(ERROR) << "Number of opened input audio streams " |
| 205 << num_input_streams_ | 205 << num_input_streams_ |
| (...skipping 21 matching lines...) Expand all Loading... |
| 227 ++num_input_streams_; | 227 ++num_input_streams_; |
| 228 } | 228 } |
| 229 | 229 |
| 230 return stream; | 230 return stream; |
| 231 } | 231 } |
| 232 | 232 |
| 233 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( | 233 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( |
| 234 const AudioParameters& params, | 234 const AudioParameters& params, |
| 235 const std::string& device_id, | 235 const std::string& device_id, |
| 236 const std::string& input_device_id) { | 236 const std::string& input_device_id) { |
| 237 DCHECK(message_loop_->BelongsToCurrentThread()); | 237 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 238 | 238 |
| 239 // 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, |
| 240 // 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 |
| 241 // 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 |
| 242 // "default" or via the specific id. | 242 // "default" or via the specific id. |
| 243 // NOTE: Implementations that don't yet support opening non-default output | 243 // NOTE: Implementations that don't yet support opening non-default output |
| 244 // devices may return an empty string from GetDefaultOutputDeviceID(). | 244 // devices may return an empty string from GetDefaultOutputDeviceID(). |
| 245 std::string output_device_id = device_id.empty() ? | 245 std::string output_device_id = device_id.empty() ? |
| 246 GetDefaultOutputDeviceID() : device_id; | 246 GetDefaultOutputDeviceID() : device_id; |
| 247 | 247 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { | 325 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { |
| 326 DCHECK(stream); | 326 DCHECK(stream); |
| 327 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. | 327 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. |
| 328 --num_input_streams_; | 328 --num_input_streams_; |
| 329 delete stream; | 329 delete stream; |
| 330 } | 330 } |
| 331 | 331 |
| 332 void AudioManagerBase::Shutdown() { | 332 void AudioManagerBase::Shutdown() { |
| 333 // Only true when we're sharing the UI message loop with the browser. The UI | 333 // Only true when we're sharing the UI message loop with the browser. The UI |
| 334 // loop is no longer running at this time and browser destruction is imminent. | 334 // loop is no longer running at this time and browser destruction is imminent. |
| 335 if (message_loop_->BelongsToCurrentThread()) { | 335 if (task_runner_->BelongsToCurrentThread()) { |
| 336 ShutdownOnAudioThread(); | 336 ShutdownOnAudioThread(); |
| 337 } else { | 337 } else { |
| 338 message_loop_->PostTask(FROM_HERE, base::Bind( | 338 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 339 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); | 339 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); |
| 340 } | 340 } |
| 341 | 341 |
| 342 // Stop() will wait for any posted messages to be processed first. | 342 // Stop() will wait for any posted messages to be processed first. |
| 343 audio_thread_.Stop(); | 343 audio_thread_.Stop(); |
| 344 } | 344 } |
| 345 | 345 |
| 346 void AudioManagerBase::ShutdownOnAudioThread() { | 346 void AudioManagerBase::ShutdownOnAudioThread() { |
| 347 DCHECK(message_loop_->BelongsToCurrentThread()); | 347 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 348 | 348 |
| 349 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); | 349 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); |
| 350 for (; it != output_dispatchers_.end(); ++it) { | 350 for (; it != output_dispatchers_.end(); ++it) { |
| 351 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; | 351 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; |
| 352 dispatcher->Shutdown(); | 352 dispatcher->Shutdown(); |
| 353 | 353 |
| 354 // All AudioOutputProxies must have been freed before Shutdown is called. | 354 // All AudioOutputProxies must have been freed before Shutdown is called. |
| 355 // If they still exist, things will go bad. They have direct pointers to | 355 // If they still exist, things will go bad. They have direct pointers to |
| 356 // both physical audio stream objects that belong to the dispatcher as | 356 // both physical audio stream objects that belong to the dispatcher as |
| 357 // well as the message loop of the audio thread that will soon go away. | 357 // well as the message loop of the audio thread that will soon go away. |
| 358 // So, better crash now than later. | 358 // So, better crash now than later. |
| 359 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; | 359 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; |
| 360 dispatcher = NULL; | 360 dispatcher = NULL; |
| 361 } | 361 } |
| 362 | 362 |
| 363 output_dispatchers_.clear(); | 363 output_dispatchers_.clear(); |
| 364 } | 364 } |
| 365 | 365 |
| 366 void AudioManagerBase::AddOutputDeviceChangeListener( | 366 void AudioManagerBase::AddOutputDeviceChangeListener( |
| 367 AudioDeviceListener* listener) { | 367 AudioDeviceListener* listener) { |
| 368 DCHECK(message_loop_->BelongsToCurrentThread()); | 368 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 369 output_listeners_.AddObserver(listener); | 369 output_listeners_.AddObserver(listener); |
| 370 } | 370 } |
| 371 | 371 |
| 372 void AudioManagerBase::RemoveOutputDeviceChangeListener( | 372 void AudioManagerBase::RemoveOutputDeviceChangeListener( |
| 373 AudioDeviceListener* listener) { | 373 AudioDeviceListener* listener) { |
| 374 DCHECK(message_loop_->BelongsToCurrentThread()); | 374 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 375 output_listeners_.RemoveObserver(listener); | 375 output_listeners_.RemoveObserver(listener); |
| 376 } | 376 } |
| 377 | 377 |
| 378 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { | 378 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { |
| 379 DCHECK(message_loop_->BelongsToCurrentThread()); | 379 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 380 DVLOG(1) << "Firing OnDeviceChange() notifications."; | 380 DVLOG(1) << "Firing OnDeviceChange() notifications."; |
| 381 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); | 381 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); |
| 382 } | 382 } |
| 383 | 383 |
| 384 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { | 384 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { |
| 385 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), | 385 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), |
| 386 AudioParameters()); | 386 AudioParameters()); |
| 387 } | 387 } |
| 388 | 388 |
| 389 AudioParameters AudioManagerBase::GetOutputStreamParameters( | 389 AudioParameters AudioManagerBase::GetOutputStreamParameters( |
| (...skipping 28 matching lines...) Expand all Loading... |
| 418 | 418 |
| 419 return 0; | 419 return 0; |
| 420 } | 420 } |
| 421 | 421 |
| 422 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog( | 422 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog( |
| 423 AudioLogFactory::AudioComponent component) { | 423 AudioLogFactory::AudioComponent component) { |
| 424 return audio_log_factory_->CreateAudioLog(component); | 424 return audio_log_factory_->CreateAudioLog(component); |
| 425 } | 425 } |
| 426 | 426 |
| 427 void AudioManagerBase::FixWedgedAudio() { | 427 void AudioManagerBase::FixWedgedAudio() { |
| 428 DCHECK(message_loop_->BelongsToCurrentThread()); | 428 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 429 #if defined(OS_MACOSX) | 429 #if defined(OS_MACOSX) |
| 430 // Through trial and error, we've found that one way to restore audio after a | 430 // Through trial and error, we've found that one way to restore audio after a |
| 431 // hang is to close all outstanding audio streams. Once all streams have been | 431 // hang is to close all outstanding audio streams. Once all streams have been |
| 432 // closed, new streams appear to work correctly. | 432 // closed, new streams appear to work correctly. |
| 433 // | 433 // |
| 434 // In Chrome terms, this means we need to ask all AudioOutputDispatchers to | 434 // In Chrome terms, this means we need to ask all AudioOutputDispatchers to |
| 435 // close all Open()'d streams. Once all streams across all dispatchers have | 435 // close all Open()'d streams. Once all streams across all dispatchers have |
| 436 // been closed, we ask for all previously Start()'d streams to be recreated | 436 // been closed, we ask for all previously Start()'d streams to be recreated |
| 437 // using the same AudioSourceCallback they had before. | 437 // using the same AudioSourceCallback they had before. |
| 438 // | 438 // |
| 439 // Since this operation takes place on the audio thread we can be sure that no | 439 // Since this operation takes place on the audio thread we can be sure that no |
| 440 // other state-changing stream operations will take place while the fix is in | 440 // other state-changing stream operations will take place while the fix is in |
| 441 // progress. | 441 // progress. |
| 442 // | 442 // |
| 443 // See http://crbug.com/160920 for additional details. | 443 // See http://crbug.com/160920 for additional details. |
| 444 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); | 444 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); |
| 445 it != output_dispatchers_.end(); ++it) { | 445 it != output_dispatchers_.end(); ++it) { |
| 446 (*it)->dispatcher->CloseStreamsForWedgeFix(); | 446 (*it)->dispatcher->CloseStreamsForWedgeFix(); |
| 447 } | 447 } |
| 448 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); | 448 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); |
| 449 it != output_dispatchers_.end(); ++it) { | 449 it != output_dispatchers_.end(); ++it) { |
| 450 (*it)->dispatcher->RestartStreamsForWedgeFix(); | 450 (*it)->dispatcher->RestartStreamsForWedgeFix(); |
| 451 } | 451 } |
| 452 #endif | 452 #endif |
| 453 } | 453 } |
| 454 | 454 |
| 455 } // namespace media | 455 } // namespace media |
| OLD | NEW |