Chromium Code Reviews| 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/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
| 10 #include "base/threading/thread.h" | 10 #include "base/threading/thread.h" |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 | 25 |
| 26 // Default maximum number of input streams that can be open simultaneously | 26 // Default maximum number of input streams that can be open simultaneously |
| 27 // for all platforms. | 27 // for all platforms. |
| 28 static const int kDefaultMaxInputStreams = 16; | 28 static const int kDefaultMaxInputStreams = 16; |
| 29 | 29 |
| 30 static const int kMaxInputChannels = 2; | 30 static const int kMaxInputChannels = 2; |
| 31 | 31 |
| 32 const char AudioManagerBase::kDefaultDeviceName[] = "Default"; | 32 const char AudioManagerBase::kDefaultDeviceName[] = "Default"; |
| 33 const char AudioManagerBase::kDefaultDeviceId[] = "default"; | 33 const char AudioManagerBase::kDefaultDeviceId[] = "default"; |
| 34 | 34 |
| 35 struct AudioManagerBase::DispatcherParams { | |
| 36 DispatcherParams(const AudioParameters& input, | |
| 37 const AudioParameters& output, | |
| 38 const std::string& device_id) | |
| 39 : input_params(input), | |
| 40 output_params(output), | |
| 41 input_device_id(device_id) {} | |
| 42 ~DispatcherParams() {} | |
| 43 | |
| 44 const AudioParameters input_params; | |
| 45 const AudioParameters output_params; | |
| 46 const std::string input_device_id; | |
| 47 scoped_refptr<AudioOutputDispatcher> dispatcher; | |
| 48 | |
| 49 private: | |
| 50 DISALLOW_COPY_AND_ASSIGN(DispatcherParams); | |
| 51 }; | |
| 52 | |
| 53 class AudioManagerBase::CompareByParams { | |
| 54 public: | |
| 55 explicit CompareByParams(const DispatcherParams* dispatcher) | |
| 56 : dispatcher_(dispatcher) {} | |
| 57 bool operator()(DispatcherParams* dispatcher_in) const { | |
| 58 // We will reuse the existing dispatcher when: | |
| 59 // 1) Unified IO is not used, input_params and output_params of the | |
| 60 // existing dispatcher are the same as the requested dispatcher. | |
| 61 // 2) Unified IO is used, input_params, output_params and input_device_id | |
| 62 // of the existing dispatcher are the same as the request dispatcher. | |
| 63 return (dispatcher_->input_params == dispatcher_in->input_params && | |
| 64 dispatcher_->output_params == dispatcher_in->output_params && | |
| 65 (!dispatcher_->input_params.input_channels() || | |
| 66 dispatcher_->input_device_id == dispatcher_in->input_device_id)); | |
| 67 } | |
| 68 | |
| 69 private: | |
| 70 const DispatcherParams* dispatcher_; | |
| 71 }; | |
| 72 | |
| 35 AudioManagerBase::AudioManagerBase() | 73 AudioManagerBase::AudioManagerBase() |
| 36 : num_active_input_streams_(0), | 74 : num_active_input_streams_(0), |
| 37 max_num_output_streams_(kDefaultMaxOutputStreams), | 75 max_num_output_streams_(kDefaultMaxOutputStreams), |
| 38 max_num_input_streams_(kDefaultMaxInputStreams), | 76 max_num_input_streams_(kDefaultMaxInputStreams), |
| 39 num_output_streams_(0), | 77 num_output_streams_(0), |
| 40 num_input_streams_(0), | 78 num_input_streams_(0), |
| 41 output_listeners_( | 79 output_listeners_( |
| 42 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), | 80 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY), |
| 43 audio_thread_(new base::Thread("AudioThread")) { | 81 audio_thread_(new base::Thread("AudioThread")) { |
| 44 #if defined(OS_WIN) | 82 #if defined(OS_WIN) |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 70 | 108 |
| 71 string16 AudioManagerBase::GetAudioInputDeviceModel() { | 109 string16 AudioManagerBase::GetAudioInputDeviceModel() { |
| 72 return string16(); | 110 return string16(); |
| 73 } | 111 } |
| 74 | 112 |
| 75 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { | 113 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { |
| 76 return message_loop_; | 114 return message_loop_; |
| 77 } | 115 } |
| 78 | 116 |
| 79 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( | 117 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( |
| 80 const AudioParameters& params) { | 118 const AudioParameters& params, |
| 119 const std::string& input_device_id) { | |
| 81 // TODO(miu): Fix ~50 call points across several unit test modules to call | 120 // TODO(miu): Fix ~50 call points across several unit test modules to call |
| 82 // this method on the audio thread, then uncomment the following: | 121 // this method on the audio thread, then uncomment the following: |
| 83 // DCHECK(message_loop_->BelongsToCurrentThread()); | 122 // DCHECK(message_loop_->BelongsToCurrentThread()); |
| 84 | 123 |
| 85 if (!params.IsValid()) { | 124 if (!params.IsValid()) { |
| 86 DLOG(ERROR) << "Audio parameters are invalid"; | 125 DLOG(ERROR) << "Audio parameters are invalid"; |
| 87 return NULL; | 126 return NULL; |
| 88 } | 127 } |
| 89 | 128 |
| 90 // Limit the number of audio streams opened. This is to prevent using | 129 // Limit the number of audio streams opened. This is to prevent using |
| 91 // excessive resources for a large number of audio streams. More | 130 // excessive resources for a large number of audio streams. More |
| 92 // importantly it prevents instability on certain systems. | 131 // importantly it prevents instability on certain systems. |
| 93 // See bug: http://crbug.com/30242. | 132 // See bug: http://crbug.com/30242. |
| 94 if (num_output_streams_ >= max_num_output_streams_) { | 133 if (num_output_streams_ >= max_num_output_streams_) { |
| 95 DLOG(ERROR) << "Number of opened output audio streams " | 134 DLOG(ERROR) << "Number of opened output audio streams " |
| 96 << num_output_streams_ | 135 << num_output_streams_ |
| 97 << " exceed the max allowed number " | 136 << " exceed the max allowed number " |
| 98 << max_num_output_streams_; | 137 << max_num_output_streams_; |
| 99 return NULL; | 138 return NULL; |
| 100 } | 139 } |
| 101 | 140 |
| 102 AudioOutputStream* stream; | 141 AudioOutputStream* stream; |
| 103 switch (params.format()) { | 142 switch (params.format()) { |
| 104 case AudioParameters::AUDIO_PCM_LINEAR: | 143 case AudioParameters::AUDIO_PCM_LINEAR: |
| 105 stream = MakeLinearOutputStream(params); | 144 stream = MakeLinearOutputStream(params); |
| 106 break; | 145 break; |
| 107 case AudioParameters::AUDIO_PCM_LOW_LATENCY: | 146 case AudioParameters::AUDIO_PCM_LOW_LATENCY: |
| 108 stream = MakeLowLatencyOutputStream(params); | 147 stream = MakeLowLatencyOutputStream(params, input_device_id); |
| 109 break; | 148 break; |
| 110 case AudioParameters::AUDIO_FAKE: | 149 case AudioParameters::AUDIO_FAKE: |
| 111 stream = FakeAudioOutputStream::MakeFakeStream(this, params); | 150 stream = FakeAudioOutputStream::MakeFakeStream(this, params); |
| 112 break; | 151 break; |
| 113 default: | 152 default: |
| 114 stream = NULL; | 153 stream = NULL; |
| 115 break; | 154 break; |
| 116 } | 155 } |
| 117 | 156 |
| 118 if (stream) { | 157 if (stream) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 } | 197 } |
| 159 | 198 |
| 160 if (stream) { | 199 if (stream) { |
| 161 ++num_input_streams_; | 200 ++num_input_streams_; |
| 162 } | 201 } |
| 163 | 202 |
| 164 return stream; | 203 return stream; |
| 165 } | 204 } |
| 166 | 205 |
| 167 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( | 206 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( |
| 168 const AudioParameters& params) { | 207 const AudioParameters& params, const std::string& input_device_id) { |
| 169 #if defined(OS_IOS) | 208 #if defined(OS_IOS) |
| 170 // IOS implements audio input only. | 209 // IOS implements audio input only. |
| 171 NOTIMPLEMENTED(); | 210 NOTIMPLEMENTED(); |
| 172 return NULL; | 211 return NULL; |
| 173 #else | 212 #else |
| 174 DCHECK(message_loop_->BelongsToCurrentThread()); | 213 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 175 | 214 |
| 176 // If we're not using AudioOutputResampler our output parameters are the same | 215 // If we're not using AudioOutputResampler our output parameters are the same |
| 177 // as our input parameters. | 216 // as our input parameters. |
| 178 AudioParameters output_params = params; | 217 AudioParameters output_params = params; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 192 << output_params.frames_per_buffer(); | 231 << output_params.frames_per_buffer(); |
| 193 | 232 |
| 194 // Tell the AudioManager to create a fake output device. | 233 // Tell the AudioManager to create a fake output device. |
| 195 output_params = AudioParameters( | 234 output_params = AudioParameters( |
| 196 AudioParameters::AUDIO_FAKE, params.channel_layout(), | 235 AudioParameters::AUDIO_FAKE, params.channel_layout(), |
| 197 params.sample_rate(), params.bits_per_sample(), | 236 params.sample_rate(), params.bits_per_sample(), |
| 198 params.frames_per_buffer()); | 237 params.frames_per_buffer()); |
| 199 } | 238 } |
| 200 } | 239 } |
| 201 | 240 |
| 202 std::pair<AudioParameters, AudioParameters> dispatcher_key = | 241 DispatcherParams* dispatcher_params = |
| 203 std::make_pair(params, output_params); | 242 new DispatcherParams(params, output_params, input_device_id); |
| 204 AudioOutputDispatchersMap::iterator it = | 243 |
| 205 output_dispatchers_.find(dispatcher_key); | 244 AudioOutputDispatchers::iterator it = |
| 206 if (it != output_dispatchers_.end()) | 245 std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), |
| 207 return new AudioOutputProxy(it->second.get()); | 246 CompareByParams(dispatcher_params)); |
| 247 if (it != output_dispatchers_.end()) { | |
| 248 delete dispatcher_params; | |
| 249 return new AudioOutputProxy((*it)->dispatcher); | |
| 250 } | |
| 208 | 251 |
| 209 const base::TimeDelta kCloseDelay = | 252 const base::TimeDelta kCloseDelay = |
| 210 base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds); | 253 base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds); |
| 211 | 254 |
| 212 if (output_params.format() != AudioParameters::AUDIO_FAKE) { | 255 if (output_params.format() != AudioParameters::AUDIO_FAKE) { |
| 213 scoped_refptr<AudioOutputDispatcher> dispatcher = | 256 scoped_refptr<AudioOutputDispatcher> dispatcher = |
| 214 new AudioOutputResampler(this, params, output_params, kCloseDelay); | 257 new AudioOutputResampler(this, params, output_params, input_device_id, |
| 215 output_dispatchers_[dispatcher_key] = dispatcher; | 258 kCloseDelay); |
| 259 dispatcher_params->dispatcher = dispatcher; | |
| 216 return new AudioOutputProxy(dispatcher.get()); | 260 return new AudioOutputProxy(dispatcher.get()); |
|
Jeffrey Yasskin
2013/08/07 23:00:47
This leaks the dispatcher_params. What did you mea
no longer working on chromium
2013/08/08 08:35:00
Oh, thanks for finding it out, I am making a CL to
| |
| 217 } | 261 } |
| 218 | 262 |
| 219 scoped_refptr<AudioOutputDispatcher> dispatcher = | 263 scoped_refptr<AudioOutputDispatcher> dispatcher = |
| 220 new AudioOutputDispatcherImpl(this, output_params, kCloseDelay); | 264 new AudioOutputDispatcherImpl(this, output_params, input_device_id, |
| 221 output_dispatchers_[dispatcher_key] = dispatcher; | 265 kCloseDelay); |
| 266 dispatcher_params->dispatcher = dispatcher; | |
| 267 output_dispatchers_.push_back(dispatcher_params); | |
| 222 return new AudioOutputProxy(dispatcher.get()); | 268 return new AudioOutputProxy(dispatcher.get()); |
| 223 #endif // defined(OS_IOS) | 269 #endif // defined(OS_IOS) |
| 224 } | 270 } |
| 225 | 271 |
| 226 void AudioManagerBase::ShowAudioInputSettings() { | 272 void AudioManagerBase::ShowAudioInputSettings() { |
| 227 } | 273 } |
| 228 | 274 |
| 229 void AudioManagerBase::GetAudioInputDeviceNames( | 275 void AudioManagerBase::GetAudioInputDeviceNames( |
| 230 media::AudioDeviceNames* device_names) { | 276 media::AudioDeviceNames* device_names) { |
| 231 } | 277 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 | 331 |
| 286 void AudioManagerBase::ShutdownOnAudioThread() { | 332 void AudioManagerBase::ShutdownOnAudioThread() { |
| 287 // IOS implements audio input only. | 333 // IOS implements audio input only. |
| 288 #if defined(OS_IOS) | 334 #if defined(OS_IOS) |
| 289 return; | 335 return; |
| 290 #else | 336 #else |
| 291 // This should always be running on the audio thread, but since we've cleared | 337 // This should always be running on the audio thread, but since we've cleared |
| 292 // the audio_thread_ member pointer when we get here, we can't verify exactly | 338 // the audio_thread_ member pointer when we get here, we can't verify exactly |
| 293 // what thread we're running on. The method is not public though and only | 339 // what thread we're running on. The method is not public though and only |
| 294 // called from one place, so we'll leave it at that. | 340 // called from one place, so we'll leave it at that. |
| 295 AudioOutputDispatchersMap::iterator it = output_dispatchers_.begin(); | 341 AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); |
| 296 for (; it != output_dispatchers_.end(); ++it) { | 342 for (; it != output_dispatchers_.end(); ++it) { |
| 297 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it).second; | 343 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; |
| 298 if (dispatcher.get()) { | 344 if (dispatcher.get()) { |
| 299 dispatcher->Shutdown(); | 345 dispatcher->Shutdown(); |
| 300 // All AudioOutputProxies must have been freed before Shutdown is called. | 346 // All AudioOutputProxies must have been freed before Shutdown is called. |
| 301 // If they still exist, things will go bad. They have direct pointers to | 347 // If they still exist, things will go bad. They have direct pointers to |
| 302 // both physical audio stream objects that belong to the dispatcher as | 348 // both physical audio stream objects that belong to the dispatcher as |
| 303 // well as the message loop of the audio thread that will soon go away. | 349 // well as the message loop of the audio thread that will soon go away. |
| 304 // So, better crash now than later. | 350 // So, better crash now than later. |
| 305 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; | 351 DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive"; |
| 306 dispatcher = NULL; | 352 dispatcher = NULL; |
| 307 } | 353 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 333 return GetPreferredOutputStreamParameters(AudioParameters()); | 379 return GetPreferredOutputStreamParameters(AudioParameters()); |
| 334 } | 380 } |
| 335 | 381 |
| 336 AudioParameters AudioManagerBase::GetInputStreamParameters( | 382 AudioParameters AudioManagerBase::GetInputStreamParameters( |
| 337 const std::string& device_id) { | 383 const std::string& device_id) { |
| 338 NOTREACHED(); | 384 NOTREACHED(); |
| 339 return AudioParameters(); | 385 return AudioParameters(); |
| 340 } | 386 } |
| 341 | 387 |
| 342 } // namespace media | 388 } // namespace media |
| OLD | NEW |