audio_manager_base.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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"; 37const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback"; 38 39struct AudioManagerBase::DispatcherParams { 40 DispatcherParams(const AudioParameters& input, 41 const AudioParameters& output, 42 const std::string& output_device_id, 43 const std::string& input_device_id) 44 : input_params(input), 45 output_params(output), 46 input_device_id(input_device_id), 47 output_device_id(output_device_id) {} 48 ~DispatcherParams() {} 49 50 const AudioParameters input_params; 51 const AudioParameters output_params; 52 const std::string input_device_id; 53 const std::string output_device_id; 54 scoped_refptr<AudioOutputDispatcher> dispatcher; 55 56 private: 57 DISALLOW_COPY_AND_ASSIGN(DispatcherParams); 58}; 59 60class AudioManagerBase::CompareByParams { 61 public: 62 explicit CompareByParams(const DispatcherParams* dispatcher) 63 : dispatcher_(dispatcher) {} 64 bool operator()(DispatcherParams* dispatcher_in) const { 65 // We will reuse the existing dispatcher when: 66 // 1) Unified IO is not used, input_params and output_params of the 67 // existing dispatcher are the same as the requested dispatcher. 68 // 2) Unified IO is used, input_params, output_params and input_device_id 69 // of the existing dispatcher are the same as the request dispatcher. 70 return (dispatcher_->input_params == dispatcher_in->input_params && 71 dispatcher_->output_params == dispatcher_in->output_params && 72 dispatcher_->output_device_id == dispatcher_in->output_device_id && 73 (!dispatcher_->input_params.input_channels() || 74 dispatcher_->input_device_id == dispatcher_in->input_device_id)); 75 } 76 77 private: 78 const DispatcherParams* dispatcher_; 79}; 80 81AudioManagerBase::AudioManagerBase() 82 : max_num_output_streams_(kDefaultMaxOutputStreams), 83 max_num_input_streams_(kDefaultMaxInputStreams), 84 num_output_streams_(0), 85 num_input_streams_(0), 86 // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't 87 // block the UI thread when swapping devices. 88 output_listeners_( 89 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), 90 audio_thread_(new base::Thread("AudioThread")) { 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_.get()); 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 // To avoid running into deadlocks while we stop the thread, shut it down 334 // via a local variable while not holding the audio thread lock. 335 scoped_ptr<base::Thread> audio_thread; 336 { 337 base::AutoLock lock(audio_thread_lock_); 338 audio_thread_.swap(audio_thread); 339 } 340 341 if (!audio_thread) 342 return; 343 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. 346 if (message_loop_->BelongsToCurrentThread()) { 347 ShutdownOnAudioThread(); 348 } else { 349 message_loop_->PostTask(FROM_HERE, base::Bind( 350 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this))); 351 } 352 353 // Stop() will wait for any posted messages to be processed first. 354 audio_thread->Stop(); 355} 356 357void AudioManagerBase::ShutdownOnAudioThread() { 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 360 // what thread we're running on. The method is not public though and only 361 // called from one place, so we'll leave it at that. 362 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); 363 for (; it != output_dispatchers_.end(); ++it) { 364 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; 365 if (dispatcher.get()) { 366 dispatcher->Shutdown(); 367 // All AudioOutputProxies must have been freed before Shutdown is called. 368 // If they still exist, things will go bad. They have direct pointers to 369 // both physical audio stream objects that belong to the dispatcher as 370 // well as the message loop of the audio thread that will soon go away. 371 // So, better crash now than later. 372 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; 373 dispatcher = NULL; 374 } 375 } 376 377 output_dispatchers_.clear(); 378} 379 380void AudioManagerBase::AddOutputDeviceChangeListener( 381 AudioDeviceListener* listener) { 382 DCHECK(message_loop_->BelongsToCurrentThread()); 383 output_listeners_.AddObserver(listener); 384} 385 386void AudioManagerBase::RemoveOutputDeviceChangeListener( 387 AudioDeviceListener* listener) { 388 DCHECK(message_loop_->BelongsToCurrentThread()); 389 output_listeners_.RemoveObserver(listener); 390} 391 392void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { 393 DCHECK(message_loop_->BelongsToCurrentThread()); 394 DVLOG(1) << "Firing OnDeviceChange() notifications."; 395 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); 396} 397 398AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { 399 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(), 400 AudioParameters()); 401} 402 403AudioParameters AudioManagerBase::GetOutputStreamParameters( 404 const std::string& device_id) { 405 return GetPreferredOutputStreamParameters(device_id, 406 AudioParameters()); 407} 408 409AudioParameters AudioManagerBase::GetInputStreamParameters( 410 const std::string& device_id) { 411 NOTREACHED(); 412 return AudioParameters(); 413} 414 415std::string AudioManagerBase::GetAssociatedOutputDeviceID( 416 const std::string& input_device_id) { 417 NOTIMPLEMENTED(); 418 return ""; 419} 420 421std::string AudioManagerBase::GetDefaultOutputDeviceID() { 422 NOTIMPLEMENTED(); 423 return ""; 424} 425 426} // namespace media 427