audio_manager_base.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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 3// found in the LICENSE file. 4 5#include "media/audio/audio_manager_base.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/command_line.h" 10#include "base/message_loop/message_loop_proxy.h" 11#include "base/threading/thread.h" 12#include "build/build_config.h" 13#include "media/audio/audio_output_dispatcher_impl.h" 14#include "media/audio/audio_output_proxy.h" 15#include "media/audio/audio_output_resampler.h" 16#include "media/audio/audio_util.h" 17#include "media/audio/fake_audio_input_stream.h" 18#include "media/audio/fake_audio_output_stream.h" 19#include "media/base/media_switches.h" 20 21namespace media { 22 23static const int kStreamCloseDelaySeconds = 5; 24 25// Default maximum number of output streams that can be open simultaneously 26// for all platforms. 27static const int kDefaultMaxOutputStreams = 16; 28 29// Default maximum number of input streams that can be open simultaneously 30// for all platforms. 31static const int kDefaultMaxInputStreams = 16; 32 33static const int kMaxInputChannels = 2; 34 35const char AudioManagerBase::kDefaultDeviceName[] = "Default"; 36const char AudioManagerBase::kDefaultDeviceId[] = "default"; 37 38struct AudioManagerBase::DispatcherParams { 39 DispatcherParams(const AudioParameters& input, 40 const AudioParameters& output, 41 const std::string& output_device_id, 42 const std::string& input_device_id) 43 : input_params(input), 44 output_params(output), 45 input_device_id(input_device_id), 46 output_device_id(output_device_id) {} 47 ~DispatcherParams() {} 48 49 const AudioParameters input_params; 50 const AudioParameters output_params; 51 const std::string input_device_id; 52 const std::string output_device_id; 53 scoped_refptr<AudioOutputDispatcher> dispatcher; 54 55 private: 56 DISALLOW_COPY_AND_ASSIGN(DispatcherParams); 57}; 58 59class AudioManagerBase::CompareByParams { 60 public: 61 explicit CompareByParams(const DispatcherParams* dispatcher) 62 : dispatcher_(dispatcher) {} 63 bool operator()(DispatcherParams* dispatcher_in) const { 64 // We will reuse the existing dispatcher when: 65 // 1) Unified IO is not used, input_params and output_params of the 66 // existing dispatcher are the same as the requested dispatcher. 67 // 2) Unified IO is used, input_params, output_params and input_device_id 68 // of the existing dispatcher are the same as the request dispatcher. 69 return (dispatcher_->input_params == dispatcher_in->input_params && 70 dispatcher_->output_params == dispatcher_in->output_params && 71 dispatcher_->output_device_id == dispatcher_in->output_device_id && 72 (!dispatcher_->input_params.input_channels() || 73 dispatcher_->input_device_id == dispatcher_in->input_device_id)); 74 } 75 76 private: 77 const DispatcherParams* dispatcher_; 78}; 79 80AudioManagerBase::AudioManagerBase() 81 : max_num_output_streams_(kDefaultMaxOutputStreams), 82 max_num_input_streams_(kDefaultMaxInputStreams), 83 num_output_streams_(0), 84 num_input_streams_(0), 85 // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't 86 // block the UI thread when swapping devices. 87 output_listeners_( 88 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), 89 audio_thread_(new base::Thread("AudioThread")) { 90#if defined(OS_WIN) 91 audio_thread_->init_com_with_mta(true); 92#elif defined(OS_MACOSX) 93 // CoreAudio calls must occur on the main thread of the process, which in our 94 // case is sadly the browser UI thread. Failure to execute calls on the right 95 // thread leads to crashes and odd behavior. See http://crbug.com/158170. 96 // TODO(dalecurtis): We should require the message loop to be passed in. 97 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 98 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) && 99 base::MessageLoopProxy::current().get() && 100 base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_UI)) { 101 message_loop_ = base::MessageLoopProxy::current(); 102 return; 103 } 104#endif 105 106 CHECK(audio_thread_->Start()); 107 message_loop_ = audio_thread_->message_loop_proxy(); 108} 109 110AudioManagerBase::~AudioManagerBase() { 111 // The platform specific AudioManager implementation must have already 112 // stopped the audio thread. Otherwise, we may destroy audio streams before 113 // stopping the thread, resulting an unexpected behavior. 114 // This way we make sure activities of the audio streams are all stopped 115 // before we destroy them. 116 CHECK(!audio_thread_.get()); 117 // All the output streams should have been deleted. 118 DCHECK_EQ(0, num_output_streams_); 119 // All the input streams should have been deleted. 120 DCHECK_EQ(0, num_input_streams_); 121} 122 123string16 AudioManagerBase::GetAudioInputDeviceModel() { 124 return string16(); 125} 126 127scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { 128 return message_loop_; 129} 130 131scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() { 132 // Lazily start the worker thread. 133 if (!audio_thread_->IsRunning()) 134 CHECK(audio_thread_->Start()); 135 136 return audio_thread_->message_loop_proxy(); 137} 138 139AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( 140 const AudioParameters& params, 141 const std::string& device_id, 142 const std::string& input_device_id) { 143 // TODO(miu): Fix ~50 call points across several unit test modules to call 144 // this method on the audio thread, then uncomment the following: 145 // DCHECK(message_loop_->BelongsToCurrentThread()); 146 147 if (!params.IsValid()) { 148 DLOG(ERROR) << "Audio parameters are invalid"; 149 return NULL; 150 } 151 152 // Limit the number of audio streams opened. This is to prevent using 153 // excessive resources for a large number of audio streams. More 154 // importantly it prevents instability on certain systems. 155 // See bug: http://crbug.com/30242. 156 if (num_output_streams_ >= max_num_output_streams_) { 157 DLOG(ERROR) << "Number of opened output audio streams " 158 << num_output_streams_ 159 << " exceed the max allowed number " 160 << max_num_output_streams_; 161 return NULL; 162 } 163 164 AudioOutputStream* stream; 165 switch (params.format()) { 166 case AudioParameters::AUDIO_PCM_LINEAR: 167 DCHECK(device_id.empty()) 168 << "AUDIO_PCM_LINEAR supports only the default device."; 169 stream = MakeLinearOutputStream(params); 170 break; 171 case AudioParameters::AUDIO_PCM_LOW_LATENCY: 172 stream = MakeLowLatencyOutputStream(params, device_id, input_device_id); 173 break; 174 case AudioParameters::AUDIO_FAKE: 175 stream = FakeAudioOutputStream::MakeFakeStream(this, params); 176 break; 177 default: 178 stream = NULL; 179 break; 180 } 181 182 if (stream) { 183 ++num_output_streams_; 184 } 185 186 return stream; 187} 188 189AudioInputStream* AudioManagerBase::MakeAudioInputStream( 190 const AudioParameters& params, 191 const std::string& device_id) { 192 // TODO(miu): Fix ~20 call points across several unit test modules to call 193 // this method on the audio thread, then uncomment the following: 194 // DCHECK(message_loop_->BelongsToCurrentThread()); 195 196 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || 197 device_id.empty()) { 198 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; 199 return NULL; 200 } 201 202 if (num_input_streams_ >= max_num_input_streams_) { 203 DLOG(ERROR) << "Number of opened input audio streams " 204 << num_input_streams_ 205 << " exceed the max allowed number " << max_num_input_streams_; 206 return NULL; 207 } 208 209 AudioInputStream* stream; 210 switch (params.format()) { 211 case AudioParameters::AUDIO_PCM_LINEAR: 212 stream = MakeLinearInputStream(params, device_id); 213 break; 214 case AudioParameters::AUDIO_PCM_LOW_LATENCY: 215 stream = MakeLowLatencyInputStream(params, device_id); 216 break; 217 case AudioParameters::AUDIO_FAKE: 218 stream = FakeAudioInputStream::MakeFakeStream(this, params); 219 break; 220 default: 221 stream = NULL; 222 break; 223 } 224 225 if (stream) { 226 ++num_input_streams_; 227 } 228 229 return stream; 230} 231 232AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( 233 const AudioParameters& params, 234 const std::string& device_id, 235 const std::string& input_device_id) { 236 DCHECK(message_loop_->BelongsToCurrentThread()); 237 238 // If the caller supplied an empty device id to select the default device, 239 // we fetch the actual device id of the default device so that the lookup 240 // will find the correct device regardless of whether it was opened as 241 // "default" or via the specific id. 242 // NOTE: Implementations that don't yet support opening non-default output 243 // devices may return an empty string from GetDefaultOutputDeviceID(). 244 std::string output_device_id = device_id.empty() ? 245 GetDefaultOutputDeviceID() : device_id; 246 247 // If we're not using AudioOutputResampler our output parameters are the same 248 // as our input parameters. 249 AudioParameters output_params = params; 250 if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { 251 output_params = 252 GetPreferredOutputStreamParameters(output_device_id, params); 253 254 // Ensure we only pass on valid output parameters. 255 if (!output_params.IsValid()) { 256 // We've received invalid audio output parameters, so switch to a mock 257 // output device based on the input parameters. This may happen if the OS 258 // provided us junk values for the hardware configuration. 259 LOG(ERROR) << "Invalid audio output parameters received; using fake " 260 << "audio path. Channels: " << output_params.channels() << ", " 261 << "Sample Rate: " << output_params.sample_rate() << ", " 262 << "Bits Per Sample: " << output_params.bits_per_sample() 263 << ", Frames Per Buffer: " 264 << output_params.frames_per_buffer(); 265 266 // Tell the AudioManager to create a fake output device. 267 output_params = AudioParameters( 268 AudioParameters::AUDIO_FAKE, params.channel_layout(), 269 params.sample_rate(), params.bits_per_sample(), 270 params.frames_per_buffer()); 271 } 272 } 273 274 DispatcherParams* dispatcher_params = 275 new DispatcherParams(params, output_params, output_device_id, 276 input_device_id); 277 278 AudioOutputDispatchers::iterator it = 279 std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), 280 CompareByParams(dispatcher_params)); 281 if (it != output_dispatchers_.end()) { 282 delete dispatcher_params; 283 return new AudioOutputProxy((*it)->dispatcher.get()); 284 } 285 286 const base::TimeDelta kCloseDelay = 287 base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds); 288 scoped_refptr<AudioOutputDispatcher> dispatcher; 289 if (output_params.format() != AudioParameters::AUDIO_FAKE) { 290 dispatcher = new AudioOutputResampler(this, params, output_params, 291 output_device_id, input_device_id, 292 kCloseDelay); 293 } else { 294 dispatcher = new AudioOutputDispatcherImpl(this, output_params, 295 output_device_id, 296 input_device_id, kCloseDelay); 297 } 298 299 dispatcher_params->dispatcher = dispatcher; 300 output_dispatchers_.push_back(dispatcher_params); 301 return new AudioOutputProxy(dispatcher.get()); 302} 303 304void AudioManagerBase::ShowAudioInputSettings() { 305} 306 307void AudioManagerBase::GetAudioInputDeviceNames( 308 AudioDeviceNames* device_names) { 309} 310 311void AudioManagerBase::GetAudioOutputDeviceNames( 312 AudioDeviceNames* device_names) { 313 // TODO(joi): Remove this and keep pure virtual once implemented everywhere. 314 NOTREACHED() << "Don't use this yet, it's not ready on all platforms!"; 315} 316 317void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) { 318 DCHECK(stream); 319 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream. 320 // For example, pass the ownership to AudioManager so it can delete the 321 // streams. 322 --num_output_streams_; 323 delete stream; 324} 325 326void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { 327 DCHECK(stream); 328 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. 329 --num_input_streams_; 330 delete stream; 331} 332 333void AudioManagerBase::Shutdown() { 334 // To avoid running into deadlocks while we stop the thread, shut it down 335 // via a local variable while not holding the audio thread lock. 336 scoped_ptr<base::Thread> audio_thread; 337 { 338 base::AutoLock lock(audio_thread_lock_); 339 audio_thread_.swap(audio_thread); 340 } 341 342 if (!audio_thread) 343 return; 344 345 // Only true when we're sharing the UI message loop with the browser. The UI 346 // loop is no longer running at this time and browser destruction is imminent. 347 if (message_loop_->BelongsToCurrentThread()) { 348 ShutdownOnAudioThread(); 349 } else { 350 message_loop_->PostTask(FROM_HERE, base::Bind( 351 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); 352 } 353 354 // Stop() will wait for any posted messages to be processed first. 355 audio_thread->Stop(); 356} 357 358void AudioManagerBase::ShutdownOnAudioThread() { 359 // This should always be running on the audio thread, but since we've cleared 360 // the audio_thread_ member pointer when we get here, we can't verify exactly 361 // what thread we're running on. The method is not public though and only 362 // called from one place, so we'll leave it at that. 363 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 364 for (; it != output_dispatchers_.end(); ++it) { 365 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; 366 if (dispatcher.get()) { 367 dispatcher->Shutdown(); 368 // All AudioOutputProxies must have been freed before Shutdown is called. 369 // If they still exist, things will go bad. They have direct pointers to 370 // both physical audio stream objects that belong to the dispatcher as 371 // well as the message loop of the audio thread that will soon go away. 372 // So, better crash now than later. 373 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; 374 dispatcher = NULL; 375 } 376 } 377 378 output_dispatchers_.clear(); 379} 380 381void AudioManagerBase::AddOutputDeviceChangeListener( 382 AudioDeviceListener* listener) { 383 DCHECK(message_loop_->BelongsToCurrentThread()); 384 output_listeners_.AddObserver(listener); 385} 386 387void AudioManagerBase::RemoveOutputDeviceChangeListener( 388 AudioDeviceListener* listener) { 389 DCHECK(message_loop_->BelongsToCurrentThread()); 390 output_listeners_.RemoveObserver(listener); 391} 392 393void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { 394 DCHECK(message_loop_->BelongsToCurrentThread()); 395 DVLOG(1) << "Firing OnDeviceChange() notifications."; 396 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); 397} 398 399AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { 400 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), 401 AudioParameters()); 402} 403 404AudioParameters AudioManagerBase::GetOutputStreamParameters( 405 const std::string& device_id) { 406 return GetPreferredOutputStreamParameters(device_id, 407 AudioParameters()); 408} 409 410AudioParameters AudioManagerBase::GetInputStreamParameters( 411 const std::string& device_id) { 412 NOTREACHED(); 413 return AudioParameters(); 414} 415 416std::string AudioManagerBase::GetAssociatedOutputDeviceID( 417 const std::string& input_device_id) { 418 NOTIMPLEMENTED(); 419 return ""; 420} 421 422std::string AudioManagerBase::GetDefaultOutputDeviceID() { 423 NOTIMPLEMENTED(); 424 return ""; 425} 426 427} // namespace media 428