audio_manager_base.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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/strings/string_number_conversions.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/fake_audio_input_stream.h" 17#include "media/audio/fake_audio_output_stream.h" 18#include "media/base/media_switches.h" 19 20namespace media { 21 22static const int kStreamCloseDelaySeconds = 5; 23 24// Default maximum number of output streams that can be open simultaneously 25// for all platforms. 26static const int kDefaultMaxOutputStreams = 16; 27 28// Default maximum number of input streams that can be open simultaneously 29// for all platforms. 30static const int kDefaultMaxInputStreams = 16; 31 32static const int kMaxInputChannels = 2; 33 34const char AudioManagerBase::kDefaultDeviceName[] = "Default"; 35const char AudioManagerBase::kDefaultDeviceId[] = "default"; 36const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback"; 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(AudioLogFactory* audio_log_factory) 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_("AudioThread"), 90 audio_log_factory_(audio_log_factory) { 91#if defined(OS_WIN) 92 audio_thread_.init_com_with_mta(true); 93#elif defined(OS_MACOSX) 94 // 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 96 // 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. 98 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 99 if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) && 100 base::MessageLoopProxy::current().get() && 101 base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_UI)) { 102 message_loop_ = base::MessageLoopProxy::current(); 103 return; 104 } 105#endif 106 107 CHECK(audio_thread_.Start()); 108 message_loop_ = audio_thread_.message_loop_proxy(); 109} 110 111AudioManagerBase::~AudioManagerBase() { 112 // The platform specific AudioManager implementation must have already 113 // stopped the audio thread. Otherwise, we may destroy audio streams before 114 // stopping the thread, resulting an unexpected behavior. 115 // This way we make sure activities of the audio streams are all stopped 116 // before we destroy them. 117 CHECK(!audio_thread_.IsRunning()); 118 // All the output streams should have been deleted. 119 DCHECK_EQ(0, num_output_streams_); 120 // All the input streams should have been deleted. 121 DCHECK_EQ(0, num_input_streams_); 122} 123 124string16 AudioManagerBase::GetAudioInputDeviceModel() { 125 return string16(); 126} 127 128scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { 129 return message_loop_; 130} 131 132scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() { 133 // Lazily start the worker thread. 134 if (!audio_thread_.IsRunning()) 135 CHECK(audio_thread_.Start()); 136 137 return audio_thread_.message_loop_proxy(); 138} 139 140AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( 141 const AudioParameters& params, 142 const std::string& device_id, 143 const std::string& input_device_id) { 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: 146 // DCHECK(message_loop_->BelongsToCurrentThread()); 147 148 if (!params.IsValid()) { 149 DLOG(ERROR) << "Audio parameters are invalid"; 150 return NULL; 151 } 152 153 // Limit the number of audio streams opened. This is to prevent using 154 // excessive resources for a large number of audio streams. More 155 // importantly it prevents instability on certain systems. 156 // See bug: http://crbug.com/30242. 157 if (num_output_streams_ >= max_num_output_streams_) { 158 DLOG(ERROR) << "Number of opened output audio streams " 159 << num_output_streams_ 160 << " exceed the max allowed number " 161 << max_num_output_streams_; 162 return NULL; 163 } 164 165 AudioOutputStream* stream; 166 switch (params.format()) { 167 case AudioParameters::AUDIO_PCM_LINEAR: 168 DCHECK(device_id.empty()) 169 << "AUDIO_PCM_LINEAR supports only the default device."; 170 stream = MakeLinearOutputStream(params); 171 break; 172 case AudioParameters::AUDIO_PCM_LOW_LATENCY: 173 stream = MakeLowLatencyOutputStream(params, device_id, input_device_id); 174 break; 175 case AudioParameters::AUDIO_FAKE: 176 stream = FakeAudioOutputStream::MakeFakeStream(this, params); 177 break; 178 default: 179 stream = NULL; 180 break; 181 } 182 183 if (stream) { 184 ++num_output_streams_; 185 } 186 187 return stream; 188} 189 190AudioInputStream* AudioManagerBase::MakeAudioInputStream( 191 const AudioParameters& params, 192 const std::string& device_id) { 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: 195 // DCHECK(message_loop_->BelongsToCurrentThread()); 196 197 if (!params.IsValid() || (params.channels() > kMaxInputChannels) || 198 device_id.empty()) { 199 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; 200 return NULL; 201 } 202 203 if (num_input_streams_ >= max_num_input_streams_) { 204 DLOG(ERROR) << "Number of opened input audio streams " 205 << num_input_streams_ 206 << " exceed the max allowed number " << max_num_input_streams_; 207 return NULL; 208 } 209 210 AudioInputStream* stream; 211 switch (params.format()) { 212 case AudioParameters::AUDIO_PCM_LINEAR: 213 stream = MakeLinearInputStream(params, device_id); 214 break; 215 case AudioParameters::AUDIO_PCM_LOW_LATENCY: 216 stream = MakeLowLatencyInputStream(params, device_id); 217 break; 218 case AudioParameters::AUDIO_FAKE: 219 stream = FakeAudioInputStream::MakeFakeStream(this, params); 220 break; 221 default: 222 stream = NULL; 223 break; 224 } 225 226 if (stream) { 227 ++num_input_streams_; 228 } 229 230 return stream; 231} 232 233AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( 234 const AudioParameters& params, 235 const std::string& device_id, 236 const std::string& input_device_id) { 237 DCHECK(message_loop_->BelongsToCurrentThread()); 238 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 241 // will find the correct device regardless of whether it was opened as 242 // "default" or via the specific id. 243 // NOTE: Implementations that don't yet support opening non-default output 244 // devices may return an empty string from GetDefaultOutputDeviceID(). 245 std::string output_device_id = device_id.empty() ? 246 GetDefaultOutputDeviceID() : device_id; 247 248 // If we're not using AudioOutputResampler our output parameters are the same 249 // as our input parameters. 250 AudioParameters output_params = params; 251 if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) { 252 output_params = 253 GetPreferredOutputStreamParameters(output_device_id, params); 254 255 // Ensure we only pass on valid output parameters. 256 if (!output_params.IsValid()) { 257 // We've received invalid audio output parameters, so switch to a mock 258 // output device based on the input parameters. This may happen if the OS 259 // provided us junk values for the hardware configuration. 260 LOG(ERROR) << "Invalid audio output parameters received; using fake " 261 << "audio path. Channels: " << output_params.channels() << ", " 262 << "Sample Rate: " << output_params.sample_rate() << ", " 263 << "Bits Per Sample: " << output_params.bits_per_sample() 264 << ", Frames Per Buffer: " 265 << output_params.frames_per_buffer(); 266 267 // Tell the AudioManager to create a fake output device. 268 output_params = AudioParameters( 269 AudioParameters::AUDIO_FAKE, params.channel_layout(), 270 params.sample_rate(), params.bits_per_sample(), 271 params.frames_per_buffer()); 272 } 273 } 274 275 DispatcherParams* dispatcher_params = 276 new DispatcherParams(params, output_params, output_device_id, 277 input_device_id); 278 279 AudioOutputDispatchers::iterator it = 280 std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), 281 CompareByParams(dispatcher_params)); 282 if (it != output_dispatchers_.end()) { 283 delete dispatcher_params; 284 return new AudioOutputProxy((*it)->dispatcher.get()); 285 } 286 287 const base::TimeDelta kCloseDelay = 288 base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds); 289 scoped_refptr<AudioOutputDispatcher> dispatcher; 290 if (output_params.format() != AudioParameters::AUDIO_FAKE) { 291 dispatcher = new AudioOutputResampler(this, params, output_params, 292 output_device_id, input_device_id, 293 kCloseDelay); 294 } else { 295 dispatcher = new AudioOutputDispatcherImpl(this, output_params, 296 output_device_id, 297 input_device_id, kCloseDelay); 298 } 299 300 dispatcher_params->dispatcher = dispatcher; 301 output_dispatchers_.push_back(dispatcher_params); 302 return new AudioOutputProxy(dispatcher.get()); 303} 304 305void AudioManagerBase::ShowAudioInputSettings() { 306} 307 308void AudioManagerBase::GetAudioInputDeviceNames( 309 AudioDeviceNames* device_names) { 310} 311 312void AudioManagerBase::GetAudioOutputDeviceNames( 313 AudioDeviceNames* device_names) { 314} 315 316void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) { 317 DCHECK(stream); 318 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream. 319 // For example, pass the ownership to AudioManager so it can delete the 320 // streams. 321 --num_output_streams_; 322 delete stream; 323} 324 325void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { 326 DCHECK(stream); 327 // TODO(xians) : Have a clearer destruction path for the AudioInputStream. 328 --num_input_streams_; 329 delete stream; 330} 331 332void AudioManagerBase::Shutdown() { 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. 335 if (message_loop_->BelongsToCurrentThread()) { 336 ShutdownOnAudioThread(); 337 } else { 338 message_loop_->PostTask(FROM_HERE, base::Bind( 339 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); 340 } 341 342 // Stop() will wait for any posted messages to be processed first. 343 audio_thread_.Stop(); 344} 345 346void AudioManagerBase::ShutdownOnAudioThread() { 347 DCHECK(message_loop_->BelongsToCurrentThread()); 348 349 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 350 for (; it != output_dispatchers_.end(); ++it) { 351 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; 352 dispatcher->Shutdown(); 353 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 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. 358 // So, better crash now than later. 359 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; 360 dispatcher = NULL; 361 } 362 363 output_dispatchers_.clear(); 364} 365 366void AudioManagerBase::AddOutputDeviceChangeListener( 367 AudioDeviceListener* listener) { 368 DCHECK(message_loop_->BelongsToCurrentThread()); 369 output_listeners_.AddObserver(listener); 370} 371 372void AudioManagerBase::RemoveOutputDeviceChangeListener( 373 AudioDeviceListener* listener) { 374 DCHECK(message_loop_->BelongsToCurrentThread()); 375 output_listeners_.RemoveObserver(listener); 376} 377 378void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { 379 DCHECK(message_loop_->BelongsToCurrentThread()); 380 DVLOG(1) << "Firing OnDeviceChange() notifications."; 381 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); 382} 383 384AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { 385 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), 386 AudioParameters()); 387} 388 389AudioParameters AudioManagerBase::GetOutputStreamParameters( 390 const std::string& device_id) { 391 return GetPreferredOutputStreamParameters(device_id, 392 AudioParameters()); 393} 394 395AudioParameters AudioManagerBase::GetInputStreamParameters( 396 const std::string& device_id) { 397 NOTREACHED(); 398 return AudioParameters(); 399} 400 401std::string AudioManagerBase::GetAssociatedOutputDeviceID( 402 const std::string& input_device_id) { 403 NOTIMPLEMENTED(); 404 return ""; 405} 406 407std::string AudioManagerBase::GetDefaultOutputDeviceID() { 408 return ""; 409} 410 411int AudioManagerBase::GetUserBufferSize() { 412 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 413 int buffer_size = 0; 414 std::string buffer_size_str(cmd_line->GetSwitchValueASCII( 415 switches::kAudioBufferSize)); 416 if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0) 417 return buffer_size; 418 419 return 0; 420} 421 422scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog( 423 AudioLogFactory::AudioComponent component) { 424 DCHECK(message_loop_->BelongsToCurrentThread()); 425 return audio_log_factory_->CreateAudioLog(component); 426} 427 428void AudioManagerBase::FixWedgedAudio() { 429 DCHECK(message_loop_->BelongsToCurrentThread()); 430#if defined(OS_MACOSX) 431 // Through trial and error, we've found that one way to restore audio after a 432 // hang is to close all outstanding audio streams. Once all streams have been 433 // closed, new streams appear to work correctly. 434 // 435 // In Chrome terms, this means we need to ask all AudioOutputDispatchers to 436 // close all Open()'d streams. Once all streams across all dispatchers have 437 // been closed, we ask for all previously Start()'d streams to be recreated 438 // using the same AudioSourceCallback they had before. 439 // 440 // Since this operation takes place on the audio thread we can be sure that no 441 // other state-changing stream operations will take place while the fix is in 442 // progress. 443 // 444 // See http://crbug.com/160920 for additional details. 445 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 446 it != output_dispatchers_.end(); ++it) { 447 (*it)->dispatcher->CloseStreamsForWedgeFix(); 448 } 449 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 450 it != output_dispatchers_.end(); ++it) { 451 (*it)->dispatcher->RestartStreamsForWedgeFix(); 452 } 453#endif 454} 455 456} // namespace media 457