Delete unused downloads page asset.
[chromium-blink-merge.git] / media / audio / audio_manager_base.cc
blobebf1d3617ad6064ae45ad53780b9b90ba1124d8b
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/single_thread_task_runner.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/thread_task_runner_handle.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"
21 namespace media {
23 static const int kStreamCloseDelaySeconds = 5;
25 // Default maximum number of output streams that can be open simultaneously
26 // for all platforms.
27 static const int kDefaultMaxOutputStreams = 16;
29 // Default maximum number of input streams that can be open simultaneously
30 // for all platforms.
31 static const int kDefaultMaxInputStreams = 16;
33 static const int kMaxInputChannels = 3;
35 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
36 const char AudioManagerBase::kDefaultDeviceId[] = "default";
37 const char AudioManagerBase::kCommunicationsDeviceId[] = "communications";
38 const char AudioManagerBase::kCommunicationsDeviceName[] = "Communications";
39 const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback";
41 struct AudioManagerBase::DispatcherParams {
42 DispatcherParams(const AudioParameters& input,
43 const AudioParameters& output,
44 const std::string& output_device_id)
45 : input_params(input),
46 output_params(output),
47 output_device_id(output_device_id) {}
48 ~DispatcherParams() {}
50 const AudioParameters input_params;
51 const AudioParameters output_params;
52 const std::string output_device_id;
53 scoped_refptr<AudioOutputDispatcher> dispatcher;
55 private:
56 DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
59 class AudioManagerBase::CompareByParams {
60 public:
61 explicit CompareByParams(const DispatcherParams* dispatcher)
62 : dispatcher_(dispatcher) {}
63 bool operator()(DispatcherParams* dispatcher_in) const {
64 // We will reuse the existing dispatcher when:
65 // 1) Unified IO is not used, input_params and output_params of the
66 // existing dispatcher are the same as the requested dispatcher.
67 // 2) Unified IO is used, input_params and output_params of the existing
68 // dispatcher are the same as the request dispatcher.
69 return (dispatcher_->input_params.Equals(dispatcher_in->input_params) &&
70 dispatcher_->output_params.Equals(dispatcher_in->output_params) &&
71 dispatcher_->output_device_id == dispatcher_in->output_device_id);
74 private:
75 const DispatcherParams* dispatcher_;
78 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
79 : max_num_output_streams_(kDefaultMaxOutputStreams),
80 max_num_input_streams_(kDefaultMaxInputStreams),
81 num_output_streams_(0),
82 num_input_streams_(0),
83 // TODO(dalecurtis): Switch this to an base::ObserverListThreadSafe, so we
84 // don't
85 // block the UI thread when swapping devices.
86 output_listeners_(
87 base::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 if (base::MessageLoopForUI::IsCurrent()) {
98 task_runner_ = base::ThreadTaskRunnerHandle::Get();
99 return;
101 #endif
103 CHECK(audio_thread_.Start());
104 task_runner_ = audio_thread_.task_runner();
107 AudioManagerBase::~AudioManagerBase() {
108 // The platform specific AudioManager implementation must have already
109 // stopped the audio thread. Otherwise, we may destroy audio streams before
110 // stopping the thread, resulting an unexpected behavior.
111 // This way we make sure activities of the audio streams are all stopped
112 // before we destroy them.
113 CHECK(!audio_thread_.IsRunning());
114 // All the output streams should have been deleted.
115 DCHECK_EQ(0, num_output_streams_);
116 // All the input streams should have been deleted.
117 DCHECK_EQ(0, num_input_streams_);
120 base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
121 return base::string16();
124 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
125 return task_runner_;
128 scoped_refptr<base::SingleThreadTaskRunner>
129 AudioManagerBase::GetWorkerTaskRunner() {
130 // Lazily start the worker thread.
131 if (!audio_thread_.IsRunning())
132 CHECK(audio_thread_.Start());
134 return audio_thread_.task_runner();
137 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
138 const AudioParameters& params,
139 const std::string& device_id) {
140 // TODO(miu): Fix ~50 call points across several unit test modules to call
141 // this method on the audio thread, then uncomment the following:
142 // DCHECK(task_runner_->BelongsToCurrentThread());
144 if (!params.IsValid()) {
145 DLOG(ERROR) << "Audio parameters are invalid";
146 return NULL;
149 // Limit the number of audio streams opened. This is to prevent using
150 // excessive resources for a large number of audio streams. More
151 // importantly it prevents instability on certain systems.
152 // See bug: http://crbug.com/30242.
153 if (num_output_streams_ >= max_num_output_streams_) {
154 DLOG(ERROR) << "Number of opened output audio streams "
155 << num_output_streams_
156 << " exceed the max allowed number "
157 << max_num_output_streams_;
158 return NULL;
161 AudioOutputStream* stream;
162 switch (params.format()) {
163 case AudioParameters::AUDIO_PCM_LINEAR:
164 DCHECK(device_id.empty())
165 << "AUDIO_PCM_LINEAR supports only the default device.";
166 stream = MakeLinearOutputStream(params);
167 break;
168 case AudioParameters::AUDIO_PCM_LOW_LATENCY:
169 stream = MakeLowLatencyOutputStream(params, device_id);
170 break;
171 case AudioParameters::AUDIO_FAKE:
172 stream = FakeAudioOutputStream::MakeFakeStream(this, params);
173 break;
174 default:
175 stream = NULL;
176 break;
179 if (stream) {
180 ++num_output_streams_;
183 return stream;
186 AudioInputStream* AudioManagerBase::MakeAudioInputStream(
187 const AudioParameters& params,
188 const std::string& device_id) {
189 // TODO(miu): Fix ~20 call points across several unit test modules to call
190 // this method on the audio thread, then uncomment the following:
191 // DCHECK(task_runner_->BelongsToCurrentThread());
193 if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
194 device_id.empty()) {
195 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
196 return NULL;
199 if (num_input_streams_ >= max_num_input_streams_) {
200 DLOG(ERROR) << "Number of opened input audio streams "
201 << num_input_streams_
202 << " exceed the max allowed number " << max_num_input_streams_;
203 return NULL;
206 DVLOG(2) << "Creating a new AudioInputStream with buffer size = "
207 << params.frames_per_buffer();
209 AudioInputStream* stream;
210 switch (params.format()) {
211 case AudioParameters::AUDIO_PCM_LINEAR:
212 stream = MakeLinearInputStream(params, device_id);
213 break;
214 case AudioParameters::AUDIO_PCM_LOW_LATENCY:
215 stream = MakeLowLatencyInputStream(params, device_id);
216 break;
217 case AudioParameters::AUDIO_FAKE:
218 stream = FakeAudioInputStream::MakeFakeStream(this, params);
219 break;
220 default:
221 stream = NULL;
222 break;
225 if (stream) {
226 ++num_input_streams_;
229 return stream;
232 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
233 const AudioParameters& params,
234 const std::string& device_id) {
235 DCHECK(task_runner_->BelongsToCurrentThread());
237 // If the caller supplied an empty device id to select the default device,
238 // we fetch the actual device id of the default device so that the lookup
239 // will find the correct device regardless of whether it was opened as
240 // "default" or via the specific id.
241 // NOTE: Implementations that don't yet support opening non-default output
242 // devices may return an empty string from GetDefaultOutputDeviceID().
243 std::string output_device_id = device_id.empty() ?
244 GetDefaultOutputDeviceID() : device_id;
246 // If we're not using AudioOutputResampler our output parameters are the same
247 // as our input parameters.
248 AudioParameters output_params = params;
249 if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
250 output_params =
251 GetPreferredOutputStreamParameters(output_device_id, params);
253 // Ensure we only pass on valid output parameters.
254 if (!output_params.IsValid()) {
255 // We've received invalid audio output parameters, so switch to a mock
256 // output device based on the input parameters. This may happen if the OS
257 // provided us junk values for the hardware configuration.
258 LOG(ERROR) << "Invalid audio output parameters received; using fake "
259 << "audio path. Channels: " << output_params.channels() << ", "
260 << "Sample Rate: " << output_params.sample_rate() << ", "
261 << "Bits Per Sample: " << output_params.bits_per_sample()
262 << ", Frames Per Buffer: "
263 << output_params.frames_per_buffer();
265 // Tell the AudioManager to create a fake output device.
266 output_params = AudioParameters(
267 AudioParameters::AUDIO_FAKE, params.channel_layout(),
268 params.sample_rate(), params.bits_per_sample(),
269 params.frames_per_buffer(), params.effects());
270 } else if (params.effects() != output_params.effects()) {
271 // Turn off effects that weren't requested.
272 output_params = AudioParameters(
273 output_params.format(), output_params.channel_layout(),
274 output_params.channels(), output_params.sample_rate(),
275 output_params.bits_per_sample(), output_params.frames_per_buffer(),
276 params.effects() & output_params.effects());
280 DispatcherParams* dispatcher_params =
281 new DispatcherParams(params, output_params, output_device_id);
283 AudioOutputDispatchers::iterator it =
284 std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
285 CompareByParams(dispatcher_params));
286 if (it != output_dispatchers_.end()) {
287 delete dispatcher_params;
288 return new AudioOutputProxy((*it)->dispatcher.get());
291 const base::TimeDelta kCloseDelay =
292 base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
293 scoped_refptr<AudioOutputDispatcher> dispatcher;
294 if (output_params.format() != AudioParameters::AUDIO_FAKE) {
295 dispatcher = new AudioOutputResampler(this, params, output_params,
296 output_device_id,
297 kCloseDelay);
298 } else {
299 dispatcher = new AudioOutputDispatcherImpl(this, output_params,
300 output_device_id,
301 kCloseDelay);
304 dispatcher_params->dispatcher = dispatcher;
305 output_dispatchers_.push_back(dispatcher_params);
306 return new AudioOutputProxy(dispatcher.get());
309 void AudioManagerBase::ShowAudioInputSettings() {
312 void AudioManagerBase::GetAudioInputDeviceNames(
313 AudioDeviceNames* device_names) {
316 void AudioManagerBase::GetAudioOutputDeviceNames(
317 AudioDeviceNames* device_names) {
320 void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
321 DCHECK(stream);
322 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
323 // For example, pass the ownership to AudioManager so it can delete the
324 // streams.
325 --num_output_streams_;
326 delete stream;
329 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
330 DCHECK(stream);
331 // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
332 --num_input_streams_;
333 delete stream;
336 void AudioManagerBase::Shutdown() {
337 // Only true when we're sharing the UI message loop with the browser. The UI
338 // loop is no longer running at this time and browser destruction is imminent.
339 if (task_runner_->BelongsToCurrentThread()) {
340 ShutdownOnAudioThread();
341 } else {
342 task_runner_->PostTask(FROM_HERE, base::Bind(
343 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
346 // Stop() will wait for any posted messages to be processed first.
347 audio_thread_.Stop();
350 void AudioManagerBase::ShutdownOnAudioThread() {
351 DCHECK(task_runner_->BelongsToCurrentThread());
352 while (!output_dispatchers_.empty()) {
353 output_dispatchers_.back()->dispatcher->Shutdown();
354 output_dispatchers_.pop_back();
358 void AudioManagerBase::AddOutputDeviceChangeListener(
359 AudioDeviceListener* listener) {
360 DCHECK(task_runner_->BelongsToCurrentThread());
361 output_listeners_.AddObserver(listener);
364 void AudioManagerBase::RemoveOutputDeviceChangeListener(
365 AudioDeviceListener* listener) {
366 DCHECK(task_runner_->BelongsToCurrentThread());
367 output_listeners_.RemoveObserver(listener);
370 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
371 DCHECK(task_runner_->BelongsToCurrentThread());
372 DVLOG(1) << "Firing OnDeviceChange() notifications.";
373 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
376 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
377 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
378 AudioParameters());
381 AudioParameters AudioManagerBase::GetOutputStreamParameters(
382 const std::string& device_id) {
383 return GetPreferredOutputStreamParameters(device_id,
384 AudioParameters());
387 AudioParameters AudioManagerBase::GetInputStreamParameters(
388 const std::string& device_id) {
389 NOTREACHED();
390 return AudioParameters();
393 std::string AudioManagerBase::GetAssociatedOutputDeviceID(
394 const std::string& input_device_id) {
395 return "";
398 std::string AudioManagerBase::GetDefaultOutputDeviceID() {
399 return "";
402 int AudioManagerBase::GetUserBufferSize() {
403 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
404 int buffer_size = 0;
405 std::string buffer_size_str(cmd_line->GetSwitchValueASCII(
406 switches::kAudioBufferSize));
407 if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0)
408 return buffer_size;
410 return 0;
413 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
414 AudioLogFactory::AudioComponent component) {
415 return audio_log_factory_->CreateAudioLog(component);
418 void AudioManagerBase::SetHasKeyboardMic() {
419 NOTREACHED();
422 } // namespace media