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