| 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 "base/threading/thread.h" | 11 #include "base/threading/thread.h" |
| 13 #include "build/build_config.h" | 12 #include "build/build_config.h" |
| 14 #include "media/audio/audio_output_dispatcher_impl.h" | 13 #include "media/audio/audio_output_dispatcher_impl.h" |
| 15 #include "media/audio/audio_output_proxy.h" | 14 #include "media/audio/audio_output_proxy.h" |
| 16 #include "media/audio/audio_output_resampler.h" | 15 #include "media/audio/audio_output_resampler.h" |
| 17 #include "media/audio/fake_audio_input_stream.h" | 16 #include "media/audio/fake_audio_input_stream.h" |
| 18 #include "media/audio/fake_audio_output_stream.h" | 17 #include "media/audio/fake_audio_output_stream.h" |
| 19 #include "media/base/media_switches.h" | 18 #include "media/base/media_switches.h" |
| 20 | 19 |
| (...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_.get()); | 116 CHECK(!audio_thread_.get()); |
| 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 string16 AudioManagerBase::GetAudioInputDeviceModel() { | 123 string16 AudioManagerBase::GetAudioInputDeviceModel() { |
| 125 return string16(); | 124 return 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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 { | 336 { |
| 337 base::AutoLock lock(audio_thread_lock_); | 337 base::AutoLock lock(audio_thread_lock_); |
| 338 audio_thread_.swap(audio_thread); | 338 audio_thread_.swap(audio_thread); |
| 339 } | 339 } |
| 340 | 340 |
| 341 if (!audio_thread) | 341 if (!audio_thread) |
| 342 return; | 342 return; |
| 343 | 343 |
| 344 // Only true when we're sharing the UI message loop with the browser. The UI | 344 // Only true when we're sharing the UI message loop with the browser. The UI |
| 345 // loop is no longer running at this time and browser destruction is imminent. | 345 // loop is no longer running at this time and browser destruction is imminent. |
| 346 if (message_loop_->BelongsToCurrentThread()) { | 346 if (task_runner_->BelongsToCurrentThread()) { |
| 347 ShutdownOnAudioThread(); | 347 ShutdownOnAudioThread(); |
| 348 } else { | 348 } else { |
| 349 message_loop_->PostTask(FROM_HERE, base::Bind( | 349 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 350 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); | 350 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); |
| 351 } | 351 } |
| 352 | 352 |
| 353 // Stop() will wait for any posted messages to be processed first. | 353 // Stop() will wait for any posted messages to be processed first. |
| 354 audio_thread->Stop(); | 354 audio_thread->Stop(); |
| 355 } | 355 } |
| 356 | 356 |
| 357 void AudioManagerBase::ShutdownOnAudioThread() { | 357 void AudioManagerBase::ShutdownOnAudioThread() { |
| 358 // This should always be running on the audio thread, but since we've cleared | 358 // This should always be running on the audio thread, but since we've cleared |
| 359 // the audio_thread_ member pointer when we get here, we can't verify exactly | 359 // the audio_thread_ member pointer when we get here, we can't verify exactly |
| (...skipping 12 matching lines...) Expand all Loading... |
| 372 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; | 372 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; |
| 373 dispatcher = NULL; | 373 dispatcher = NULL; |
| 374 } | 374 } |
| 375 } | 375 } |
| 376 | 376 |
| 377 output_dispatchers_.clear(); | 377 output_dispatchers_.clear(); |
| 378 } | 378 } |
| 379 | 379 |
| 380 void AudioManagerBase::AddOutputDeviceChangeListener( | 380 void AudioManagerBase::AddOutputDeviceChangeListener( |
| 381 AudioDeviceListener* listener) { | 381 AudioDeviceListener* listener) { |
| 382 DCHECK(message_loop_->BelongsToCurrentThread()); | 382 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 383 output_listeners_.AddObserver(listener); | 383 output_listeners_.AddObserver(listener); |
| 384 } | 384 } |
| 385 | 385 |
| 386 void AudioManagerBase::RemoveOutputDeviceChangeListener( | 386 void AudioManagerBase::RemoveOutputDeviceChangeListener( |
| 387 AudioDeviceListener* listener) { | 387 AudioDeviceListener* listener) { |
| 388 DCHECK(message_loop_->BelongsToCurrentThread()); | 388 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 389 output_listeners_.RemoveObserver(listener); | 389 output_listeners_.RemoveObserver(listener); |
| 390 } | 390 } |
| 391 | 391 |
| 392 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { | 392 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { |
| 393 DCHECK(message_loop_->BelongsToCurrentThread()); | 393 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 394 DVLOG(1) << "Firing OnDeviceChange() notifications."; | 394 DVLOG(1) << "Firing OnDeviceChange() notifications."; |
| 395 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); | 395 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); |
| 396 } | 396 } |
| 397 | 397 |
| 398 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { | 398 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { |
| 399 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), | 399 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), |
| 400 AudioParameters()); | 400 AudioParameters()); |
| 401 } | 401 } |
| 402 | 402 |
| 403 AudioParameters AudioManagerBase::GetOutputStreamParameters( | 403 AudioParameters AudioManagerBase::GetOutputStreamParameters( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 428 int buffer_size = 0; | 428 int buffer_size = 0; |
| 429 std::string buffer_size_str(cmd_line->GetSwitchValueASCII( | 429 std::string buffer_size_str(cmd_line->GetSwitchValueASCII( |
| 430 switches::kAudioBufferSize)); | 430 switches::kAudioBufferSize)); |
| 431 if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0) | 431 if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0) |
| 432 return buffer_size; | 432 return buffer_size; |
| 433 | 433 |
| 434 return 0; | 434 return 0; |
| 435 } | 435 } |
| 436 | 436 |
| 437 } // namespace media | 437 } // namespace media |
| OLD | NEW |