Plugin Power Saver: Fix a nullptr crash with plugin placeholder resize.
[chromium-blink-merge.git] / media / audio / audio_manager_base.cc
blobb633432fc0eb43482abed2339803022e9248126b
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::kLoopbackInputDeviceId[] = "loopback";
39 struct AudioManagerBase::DispatcherParams {
40 DispatcherParams(const AudioParameters& input,
41 const AudioParameters& output,
42 const std::string& output_device_id)
43 : input_params(input),
44 output_params(output),
45 output_device_id(output_device_id) {}
46 ~DispatcherParams() {}
48 const AudioParameters input_params;
49 const AudioParameters output_params;
50 const std::string output_device_id;
51 scoped_refptr<AudioOutputDispatcher> dispatcher;
53 private:
54 DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
57 class AudioManagerBase::CompareByParams {
58 public:
59 explicit CompareByParams(const DispatcherParams* dispatcher)
60 : dispatcher_(dispatcher) {}
61 bool operator()(DispatcherParams* dispatcher_in) const {
62 // We will reuse the existing dispatcher when:
63 // 1) Unified IO is not used, input_params and output_params of the
64 // existing dispatcher are the same as the requested dispatcher.
65 // 2) Unified IO is used, input_params and output_params of the existing
66 // dispatcher are the same as the request dispatcher.
67 return (dispatcher_->input_params.Equals(dispatcher_in->input_params) &&
68 dispatcher_->output_params.Equals(dispatcher_in->output_params) &&
69 dispatcher_->output_device_id == dispatcher_in->output_device_id);
72 private:
73 const DispatcherParams* dispatcher_;
76 AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
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 base::ObserverListThreadSafe, so we
82 // don't
83 // block the UI thread when swapping devices.
84 output_listeners_(
85 base::ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
86 audio_thread_("AudioThread"),
87 audio_log_factory_(audio_log_factory) {
88 #if defined(OS_WIN)
89 audio_thread_.init_com_with_mta(true);
90 #elif defined(OS_MACOSX)
91 // CoreAudio calls must occur on the main thread of the process, which in our
92 // case is sadly the browser UI thread. Failure to execute calls on the right
93 // thread leads to crashes and odd behavior. See http://crbug.com/158170.
94 // TODO(dalecurtis): We should require the message loop to be passed in.
95 if (base::MessageLoopForUI::IsCurrent()) {
96 task_runner_ = base::ThreadTaskRunnerHandle::Get();
97 return;
99 #endif
101 CHECK(audio_thread_.Start());
102 task_runner_ = audio_thread_.message_loop_proxy();
105 AudioManagerBase::~AudioManagerBase() {
106 // The platform specific AudioManager implementation must have already
107 // stopped the audio thread. Otherwise, we may destroy audio streams before
108 // stopping the thread, resulting an unexpected behavior.
109 // This way we make sure activities of the audio streams are all stopped
110 // before we destroy them.
111 CHECK(!audio_thread_.IsRunning());
112 // All the output streams should have been deleted.
113 DCHECK_EQ(0, num_output_streams_);
114 // All the input streams should have been deleted.
115 DCHECK_EQ(0, num_input_streams_);
118 base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
119 return base::string16();
122 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
123 return task_runner_;
126 scoped_refptr<base::SingleThreadTaskRunner>
127 AudioManagerBase::GetWorkerTaskRunner() {
128 // Lazily start the worker thread.
129 if (!audio_thread_.IsRunning())
130 CHECK(audio_thread_.Start());
132 return audio_thread_.message_loop_proxy();
135 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
136 const AudioParameters& params,
137 const std::string& 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(task_runner_->BelongsToCurrentThread());
142 if (!params.IsValid()) {
143 DLOG(ERROR) << "Audio parameters are invalid";
144 return NULL;
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;
159 AudioOutputStream* stream;
160 switch (params.format()) {
161 case AudioParameters::AUDIO_PCM_LINEAR:
162 DCHECK(device_id.empty())
163 << "AUDIO_PCM_LINEAR supports only the default device.";
164 stream = MakeLinearOutputStream(params);
165 break;
166 case AudioParameters::AUDIO_PCM_LOW_LATENCY:
167 stream = MakeLowLatencyOutputStream(params, device_id);
168 break;
169 case AudioParameters::AUDIO_FAKE:
170 stream = FakeAudioOutputStream::MakeFakeStream(this, params);
171 break;
172 default:
173 stream = NULL;
174 break;
177 if (stream) {
178 ++num_output_streams_;
181 return stream;
184 AudioInputStream* AudioManagerBase::MakeAudioInputStream(
185 const AudioParameters& params,
186 const std::string& device_id) {
187 // TODO(miu): Fix ~20 call points across several unit test modules to call
188 // this method on the audio thread, then uncomment the following:
189 // DCHECK(task_runner_->BelongsToCurrentThread());
191 if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
192 device_id.empty()) {
193 DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
194 return NULL;
197 if (num_input_streams_ >= max_num_input_streams_) {
198 DLOG(ERROR) << "Number of opened input audio streams "
199 << num_input_streams_
200 << " exceed the max allowed number " << max_num_input_streams_;
201 return NULL;
204 DVLOG(2) << "Creating a new AudioInputStream with buffer size = "
205 << params.frames_per_buffer();
207 AudioInputStream* stream;
208 switch (params.format()) {
209 case AudioParameters::AUDIO_PCM_LINEAR:
210 stream = MakeLinearInputStream(params, device_id);
211 break;
212 case AudioParameters::AUDIO_PCM_LOW_LATENCY:
213 stream = MakeLowLatencyInputStream(params, device_id);
214 break;
215 case AudioParameters::AUDIO_FAKE:
216 stream = FakeAudioInputStream::MakeFakeStream(this, params);
217 break;
218 default:
219 stream = NULL;
220 break;
223 if (stream) {
224 ++num_input_streams_;
227 return stream;
230 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
231 const AudioParameters& params,
232 const std::string& device_id) {
233 DCHECK(task_runner_->BelongsToCurrentThread());
235 // If the caller supplied an empty device id to select the default device,
236 // we fetch the actual device id of the default device so that the lookup
237 // will find the correct device regardless of whether it was opened as
238 // "default" or via the specific id.
239 // NOTE: Implementations that don't yet support opening non-default output
240 // devices may return an empty string from GetDefaultOutputDeviceID().
241 std::string output_device_id = device_id.empty() ?
242 GetDefaultOutputDeviceID() : device_id;
244 // If we're not using AudioOutputResampler our output parameters are the same
245 // as our input parameters.
246 AudioParameters output_params = params;
247 if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
248 output_params =
249 GetPreferredOutputStreamParameters(output_device_id, params);
251 // Ensure we only pass on valid output parameters.
252 if (!output_params.IsValid()) {
253 // We've received invalid audio output parameters, so switch to a mock
254 // output device based on the input parameters. This may happen if the OS
255 // provided us junk values for the hardware configuration.
256 LOG(ERROR) << "Invalid audio output parameters received; using fake "
257 << "audio path. Channels: " << output_params.channels() << ", "
258 << "Sample Rate: " << output_params.sample_rate() << ", "
259 << "Bits Per Sample: " << output_params.bits_per_sample()
260 << ", Frames Per Buffer: "
261 << output_params.frames_per_buffer();
263 // Tell the AudioManager to create a fake output device.
264 output_params = AudioParameters(
265 AudioParameters::AUDIO_FAKE, params.channel_layout(),
266 params.sample_rate(), params.bits_per_sample(),
267 params.frames_per_buffer());
271 DispatcherParams* dispatcher_params =
272 new DispatcherParams(params, output_params, output_device_id);
274 AudioOutputDispatchers::iterator it =
275 std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
276 CompareByParams(dispatcher_params));
277 if (it != output_dispatchers_.end()) {
278 delete dispatcher_params;
279 return new AudioOutputProxy((*it)->dispatcher.get());
282 const base::TimeDelta kCloseDelay =
283 base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
284 scoped_refptr<AudioOutputDispatcher> dispatcher;
285 if (output_params.format() != AudioParameters::AUDIO_FAKE) {
286 dispatcher = new AudioOutputResampler(this, params, output_params,
287 output_device_id,
288 kCloseDelay);
289 } else {
290 dispatcher = new AudioOutputDispatcherImpl(this, output_params,
291 output_device_id,
292 kCloseDelay);
295 dispatcher_params->dispatcher = dispatcher;
296 output_dispatchers_.push_back(dispatcher_params);
297 return new AudioOutputProxy(dispatcher.get());
300 void AudioManagerBase::ShowAudioInputSettings() {
303 void AudioManagerBase::GetAudioInputDeviceNames(
304 AudioDeviceNames* device_names) {
307 void AudioManagerBase::GetAudioOutputDeviceNames(
308 AudioDeviceNames* device_names) {
311 void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
312 DCHECK(stream);
313 // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
314 // For example, pass the ownership to AudioManager so it can delete the
315 // streams.
316 --num_output_streams_;
317 delete stream;
320 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
321 DCHECK(stream);
322 // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
323 --num_input_streams_;
324 delete stream;
327 void AudioManagerBase::Shutdown() {
328 // Only true when we're sharing the UI message loop with the browser. The UI
329 // loop is no longer running at this time and browser destruction is imminent.
330 if (task_runner_->BelongsToCurrentThread()) {
331 ShutdownOnAudioThread();
332 } else {
333 task_runner_->PostTask(FROM_HERE, base::Bind(
334 &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
337 // Stop() will wait for any posted messages to be processed first.
338 audio_thread_.Stop();
341 void AudioManagerBase::ShutdownOnAudioThread() {
342 DCHECK(task_runner_->BelongsToCurrentThread());
343 while (!output_dispatchers_.empty()) {
344 output_dispatchers_.back()->dispatcher->Shutdown();
345 output_dispatchers_.pop_back();
349 void AudioManagerBase::AddOutputDeviceChangeListener(
350 AudioDeviceListener* listener) {
351 DCHECK(task_runner_->BelongsToCurrentThread());
352 output_listeners_.AddObserver(listener);
355 void AudioManagerBase::RemoveOutputDeviceChangeListener(
356 AudioDeviceListener* listener) {
357 DCHECK(task_runner_->BelongsToCurrentThread());
358 output_listeners_.RemoveObserver(listener);
361 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
362 DCHECK(task_runner_->BelongsToCurrentThread());
363 DVLOG(1) << "Firing OnDeviceChange() notifications.";
364 FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
367 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
368 return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
369 AudioParameters());
372 AudioParameters AudioManagerBase::GetOutputStreamParameters(
373 const std::string& device_id) {
374 return GetPreferredOutputStreamParameters(device_id,
375 AudioParameters());
378 AudioParameters AudioManagerBase::GetInputStreamParameters(
379 const std::string& device_id) {
380 NOTREACHED();
381 return AudioParameters();
384 std::string AudioManagerBase::GetAssociatedOutputDeviceID(
385 const std::string& input_device_id) {
386 return "";
389 std::string AudioManagerBase::GetDefaultOutputDeviceID() {
390 return "";
393 int AudioManagerBase::GetUserBufferSize() {
394 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
395 int buffer_size = 0;
396 std::string buffer_size_str(cmd_line->GetSwitchValueASCII(
397 switches::kAudioBufferSize));
398 if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0)
399 return buffer_size;
401 return 0;
404 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
405 AudioLogFactory::AudioComponent component) {
406 return audio_log_factory_->CreateAudioLog(component);
409 void AudioManagerBase::SetHasKeyboardMic() {
410 NOTREACHED();
413 } // namespace media