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"
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 "base/threading/thread.h"
13 #include "build/build_config.h"
14 #include "media/audio/audio_output_dispatcher_impl.h"
15 #include "media/audio/audio_output_proxy.h"
16 #include "media/audio/audio_output_resampler.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"
23 static const int kStreamCloseDelaySeconds
= 5;
25 // Default maximum number of output streams that can be open simultaneously
27 static const int kDefaultMaxOutputStreams
= 16;
29 // Default maximum number of input streams that can be open simultaneously
31 static const int kDefaultMaxInputStreams
= 16;
33 static const int kMaxInputChannels
= 2;
35 const char AudioManagerBase::kDefaultDeviceName
[] = "Default";
36 const char AudioManagerBase::kDefaultDeviceId
[] = "default";
37 const char AudioManagerBase::kLoopbackInputDeviceId
[] = "loopback";
39 struct 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() {}
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
;
57 DISALLOW_COPY_AND_ASSIGN(DispatcherParams
);
60 class AudioManagerBase::CompareByParams
{
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
));
78 const DispatcherParams
* dispatcher_
;
81 AudioManagerBase::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.
89 ObserverList
<AudioDeviceListener
>::NOTIFY_EXISTING_ONLY
),
90 audio_thread_(new base::Thread("AudioThread")) {
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();
107 CHECK(audio_thread_
->Start());
108 message_loop_
= audio_thread_
->message_loop_proxy();
111 AudioManagerBase::~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_
);
124 string16
AudioManagerBase::GetAudioInputDeviceModel() {
128 scoped_refptr
<base::MessageLoopProxy
> AudioManagerBase::GetMessageLoop() {
129 return message_loop_
;
132 scoped_refptr
<base::MessageLoopProxy
> AudioManagerBase::GetWorkerLoop() {
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(message_loop_->BelongsToCurrentThread());
148 if (!params
.IsValid()) {
149 DLOG(ERROR
) << "Audio parameters are invalid";
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_
;
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
);
172 case AudioParameters::AUDIO_PCM_LOW_LATENCY
:
173 stream
= MakeLowLatencyOutputStream(params
, device_id
, input_device_id
);
175 case AudioParameters::AUDIO_FAKE
:
176 stream
= FakeAudioOutputStream::MakeFakeStream(this, params
);
184 ++num_output_streams_
;
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(message_loop_->BelongsToCurrentThread());
197 if (!params
.IsValid() || (params
.channels() > kMaxInputChannels
) ||
199 DLOG(ERROR
) << "Audio parameters are invalid for device " << device_id
;
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_
;
210 AudioInputStream
* stream
;
211 switch (params
.format()) {
212 case AudioParameters::AUDIO_PCM_LINEAR
:
213 stream
= MakeLinearInputStream(params
, device_id
);
215 case AudioParameters::AUDIO_PCM_LOW_LATENCY
:
216 stream
= MakeLowLatencyInputStream(params
, device_id
);
218 case AudioParameters::AUDIO_FAKE
:
219 stream
= FakeAudioInputStream::MakeFakeStream(this, params
);
227 ++num_input_streams_
;
233 AudioOutputStream
* AudioManagerBase::MakeAudioOutputStreamProxy(
234 const AudioParameters
& params
,
235 const std::string
& device_id
,
236 const std::string
& input_device_id
) {
237 DCHECK(message_loop_
->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
) {
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
,
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
,
295 dispatcher
= new AudioOutputDispatcherImpl(this, output_params
,
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
) {
318 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
319 // For example, pass the ownership to AudioManager so it can delete the
321 --num_output_streams_
;
325 void AudioManagerBase::ReleaseInputStream(AudioInputStream
* stream
) {
327 // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
328 --num_input_streams_
;
332 void 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
;
337 base::AutoLock
lock(audio_thread_lock_
);
338 audio_thread_
.swap(audio_thread
);
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();
349 message_loop_
->PostTask(FROM_HERE
, base::Bind(
350 &AudioManagerBase::ShutdownOnAudioThread
, base::Unretained(this)));
353 // Stop() will wait for any posted messages to be processed first.
354 audio_thread
->Stop();
357 void 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";
377 output_dispatchers_
.clear();
380 void AudioManagerBase::AddOutputDeviceChangeListener(
381 AudioDeviceListener
* listener
) {
382 DCHECK(message_loop_
->BelongsToCurrentThread());
383 output_listeners_
.AddObserver(listener
);
386 void AudioManagerBase::RemoveOutputDeviceChangeListener(
387 AudioDeviceListener
* listener
) {
388 DCHECK(message_loop_
->BelongsToCurrentThread());
389 output_listeners_
.RemoveObserver(listener
);
392 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
393 DCHECK(message_loop_
->BelongsToCurrentThread());
394 DVLOG(1) << "Firing OnDeviceChange() notifications.";
395 FOR_EACH_OBSERVER(AudioDeviceListener
, output_listeners_
, OnDeviceChange());
398 AudioParameters
AudioManagerBase::GetDefaultOutputStreamParameters() {
399 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
403 AudioParameters
AudioManagerBase::GetOutputStreamParameters(
404 const std::string
& device_id
) {
405 return GetPreferredOutputStreamParameters(device_id
,
409 AudioParameters
AudioManagerBase::GetInputStreamParameters(
410 const std::string
& device_id
) {
412 return AudioParameters();
415 std::string
AudioManagerBase::GetAssociatedOutputDeviceID(
416 const std::string
& input_device_id
) {
421 std::string
AudioManagerBase::GetDefaultOutputDeviceID() {
426 int AudioManagerBase::GetUserBufferSize() {
427 const CommandLine
* cmd_line
= CommandLine::ForCurrentProcess();
429 std::string
buffer_size_str(cmd_line
->GetSwitchValueASCII(
430 switches::kAudioBufferSize
));
431 if (base::StringToInt(buffer_size_str
, &buffer_size
) && buffer_size
> 0)