Add git cl format presubmit warning for extension and apps.
[chromium-blink-merge.git] / media / audio / audio_manager_base.cc
blobf4cd60e2d06d27fe271e600d67a44497b5b34bae
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.
5 #include "media/audio/audio_manager_base.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "build/build_config.h"
12 #include "media/audio/audio_output_dispatcher_impl.h"
13 #include "media/audio/audio_output_proxy.h"
14 #include "media/audio/audio_output_resampler.h"
15 #include "media/audio/fake_audio_input_stream.h"
16 #include "media/audio/fake_audio_output_stream.h"
17 #include "media/base/media_switches.h"
19 namespace media {
21 static const int kStreamCloseDelaySeconds = 5;
23 // Default maximum number of output streams that can be open simultaneously
24 // for all platforms.
25 static const int kDefaultMaxOutputStreams = 16;
27 // Default maximum number of input streams that can be open simultaneously
28 // for all platforms.
29 static const int kDefaultMaxInputStreams = 16;
31 static const int kMaxInputChannels = 2;
33 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
34 const char AudioManagerBase::kDefaultDeviceId[] = "default";
35 const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback";
37 struct AudioManagerBase::DispatcherParams {
38 DispatcherParams(const AudioParameters& input,
39 const AudioParameters& output,
40 const std::string& output_device_id,
41 const std::string& input_device_id)
42 : input_params(input),
43 output_params(output),
44 input_device_id(input_device_id),
45 output_device_id(output_device_id) {}
46 ~DispatcherParams() {}
48 const AudioParameters input_params;
49 const AudioParameters output_params;
50 const std::string input_device_id;
51 const std::string output_device_id;
52 scoped_refptr<AudioOutputDispatcher> dispatcher;
54 private:
55 DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
58 class AudioManagerBase::CompareByParams {
59 public:
60 explicit CompareByParams(const DispatcherParams* dispatcher)
61 : dispatcher_(dispatcher) {}
62 bool operator()(DispatcherParams* dispatcher_in) const {
63 // We will reuse the existing dispatcher when:
64 // 1) Unified IO is not used, input_params and output_params of the
65 // existing dispatcher are the same as the requested dispatcher.
66 // 2) Unified IO is used, input_params, output_params and input_device_id
67 // of the existing dispatcher are the same as the request dispatcher.
68 return (dispatcher_->input_params == dispatcher_in->input_params &&
69 dispatcher_->output_params == dispatcher_in->output_params &&
70 dispatcher_->output_device_id == dispatcher_in->output_device_id &&
71 (!dispatcher_->input_params.input_channels() ||
72 dispatcher_->input_device_id == dispatcher_in->input_device_id));
75 private:
76 const DispatcherParams* dispatcher_;
79 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
80 : max_num_output_streams_(kDefaultMaxOutputStreams),
81 max_num_input_streams_(kDefaultMaxInputStreams),
82 num_output_streams_(0),
83 num_input_streams_(0),
84 // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't
85 // block the UI thread when swapping devices.
86 output_listeners_(
87 ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
88 audio_thread_("AudioThread"),
89 audio_log_factory_(audio_log_factory) {
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::MessageLoopForUI::IsCurrent()) {
101 task_runner_ = base::MessageLoopProxy::current();
102 return;
104 #endif
106 CHECK(audio_thread_.Start());
107 task_runner_ = audio_thread_.message_loop_proxy();
110 AudioManagerBase::~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_.IsRunning());
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_);
123 base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
124 return base::string16();
127 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
128 return task_runner_;
131 scoped_refptr<base::SingleThreadTaskRunner>
132 AudioManagerBase::GetWorkerTaskRunner() {
133 // Lazily start the worker thread.
134 if (!audio_thread_.IsRunning())
135 CHECK(audio_thread_.Start());
137 return audio_thread_.message_loop_proxy();
140 AudioOutputStream* 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(task_runner_->BelongsToCurrentThread());
148 if (!params.IsValid()) {
149 DLOG(ERROR) << "Audio parameters are invalid";
150 return NULL;
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;
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;
183 if (stream) {
184 ++num_output_streams_;
187 return stream;
190 AudioInputStream* 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(task_runner_->BelongsToCurrentThread());
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;
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;
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;
226 if (stream) {
227 ++num_input_streams_;
230 return stream;
233 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
234 const AudioParameters& params,
235 const std::string& device_id,
236 const std::string& input_device_id) {
237 DCHECK(task_runner_->BelongsToCurrentThread());
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;
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);
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();
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());
275 DispatcherParams* dispatcher_params =
276 new DispatcherParams(params, output_params, output_device_id,
277 input_device_id);
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());
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);
300 dispatcher_params->dispatcher = dispatcher;
301 output_dispatchers_.push_back(dispatcher_params);
302 return new AudioOutputProxy(dispatcher.get());
305 void AudioManagerBase::ShowAudioInputSettings() {
308 void AudioManagerBase::GetAudioInputDeviceNames(
309 AudioDeviceNames* device_names) {
312 void AudioManagerBase::GetAudioOutputDeviceNames(
313 AudioDeviceNames* device_names) {
316 void 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;
325 void 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;
332 void 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 (task_runner_->BelongsToCurrentThread()) {
336 ShutdownOnAudioThread();
337 } else {
338 task_runner_->PostTask(FROM_HERE, base::Bind(
339 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
342 // Stop() will wait for any posted messages to be processed first.
343 audio_thread_.Stop();
346 void AudioManagerBase::ShutdownOnAudioThread() {
347 DCHECK(task_runner_->BelongsToCurrentThread());
349 AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
350 for (; it != output_dispatchers_.end(); ++it) {
351 scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher;
352 dispatcher->Shutdown();
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;
363 output_dispatchers_.clear();
366 void AudioManagerBase::AddOutputDeviceChangeListener(
367 AudioDeviceListener* listener) {
368 DCHECK(task_runner_->BelongsToCurrentThread());
369 output_listeners_.AddObserver(listener);
372 void AudioManagerBase::RemoveOutputDeviceChangeListener(
373 AudioDeviceListener* listener) {
374 DCHECK(task_runner_->BelongsToCurrentThread());
375 output_listeners_.RemoveObserver(listener);
378 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
379 DCHECK(task_runner_->BelongsToCurrentThread());
380 DVLOG(1) << "Firing OnDeviceChange() notifications.";
381 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
384 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
385 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
386 AudioParameters());
389 AudioParameters AudioManagerBase::GetOutputStreamParameters(
390 const std::string& device_id) {
391 return GetPreferredOutputStreamParameters(device_id,
392 AudioParameters());
395 AudioParameters AudioManagerBase::GetInputStreamParameters(
396 const std::string& device_id) {
397 NOTREACHED();
398 return AudioParameters();
401 std::string AudioManagerBase::GetAssociatedOutputDeviceID(
402 const std::string& input_device_id) {
403 return "";
406 std::string AudioManagerBase::GetDefaultOutputDeviceID() {
407 return "";
410 int AudioManagerBase::GetUserBufferSize() {
411 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
412 int buffer_size = 0;
413 std::string buffer_size_str(cmd_line->GetSwitchValueASCII(
414 switches::kAudioBufferSize));
415 if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0)
416 return buffer_size;
418 return 0;
421 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
422 AudioLogFactory::AudioComponent component) {
423 return audio_log_factory_->CreateAudioLog(component);
426 void AudioManagerBase::FixWedgedAudio() {
427 DCHECK(task_runner_->BelongsToCurrentThread());
428 #if defined(OS_MACOSX)
429 // Through trial and error, we've found that one way to restore audio after a
430 // hang is to close all outstanding audio streams. Once all streams have been
431 // closed, new streams appear to work correctly.
433 // In Chrome terms, this means we need to ask all AudioOutputDispatchers to
434 // close all Open()'d streams. Once all streams across all dispatchers have
435 // been closed, we ask for all previously Start()'d streams to be recreated
436 // using the same AudioSourceCallback they had before.
438 // Since this operation takes place on the audio thread we can be sure that no
439 // other state-changing stream operations will take place while the fix is in
440 // progress.
442 // See http://crbug.com/160920 for additional details.
443 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
444 it != output_dispatchers_.end(); ++it) {
445 (*it)->dispatcher->CloseStreamsForWedgeFix();
447 for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
448 it != output_dispatchers_.end(); ++it) {
449 (*it)->dispatcher->RestartStreamsForWedgeFix();
451 #endif
454 } // namespace media