Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_manager_base.cc
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.
4
5 #include "media/audio/audio_manager_base.h"
6
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"
18
19 namespace media {
20
21 static const int kStreamCloseDelaySeconds = 5;
22
23 // Default maximum number of output streams that can be open simultaneously
24 // for all platforms.
25 static const int kDefaultMaxOutputStreams = 16;
26
27 // Default maximum number of input streams that can be open simultaneously
28 // for all platforms.
29 static const int kDefaultMaxInputStreams = 16;
30
31 static const int kMaxInputChannels = 2;
32
33 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
34 const char AudioManagerBase::kDefaultDeviceId[] = "default";
35 const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback";
36
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() {}
47
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;
53
54  private:
55   DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
56 };
57
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));
73   }
74
75  private:
76   const DispatcherParams* dispatcher_;
77 };
78
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;
103   }
104 #endif
105
106   CHECK(audio_thread_.Start());
107   task_runner_ = audio_thread_.message_loop_proxy();
108 }
109
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_);
121 }
122
123 base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
124   return base::string16();
125 }
126
127 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
128   return task_runner_;
129 }
130
131 scoped_refptr<base::SingleThreadTaskRunner>
132 AudioManagerBase::GetWorkerTaskRunner() {
133   // Lazily start the worker thread.
134   if (!audio_thread_.IsRunning())
135     CHECK(audio_thread_.Start());
136
137   return audio_thread_.message_loop_proxy();
138 }
139
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());
147
148   if (!params.IsValid()) {
149     DLOG(ERROR) << "Audio parameters are invalid";
150     return NULL;
151   }
152
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;
163   }
164
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;
181   }
182
183   if (stream) {
184     ++num_output_streams_;
185   }
186
187   return stream;
188 }
189
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());
196
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;
201   }
202
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;
208   }
209
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;
224   }
225
226   if (stream) {
227     ++num_input_streams_;
228   }
229
230   return stream;
231 }
232
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());
238
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;
247
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);
254
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();
266
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());
272     }
273   }
274
275   DispatcherParams* dispatcher_params =
276       new DispatcherParams(params, output_params, output_device_id,
277           input_device_id);
278
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());
285   }
286
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);
298   }
299
300   dispatcher_params->dispatcher = dispatcher;
301   output_dispatchers_.push_back(dispatcher_params);
302   return new AudioOutputProxy(dispatcher.get());
303 }
304
305 void AudioManagerBase::ShowAudioInputSettings() {
306 }
307
308 void AudioManagerBase::GetAudioInputDeviceNames(
309     AudioDeviceNames* device_names) {
310 }
311
312 void AudioManagerBase::GetAudioOutputDeviceNames(
313     AudioDeviceNames* device_names) {
314 }
315
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;
323 }
324
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;
330 }
331
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)));
340   }
341
342   // Stop() will wait for any posted messages to be processed first.
343   audio_thread_.Stop();
344 }
345
346 void AudioManagerBase::ShutdownOnAudioThread() {
347   DCHECK(task_runner_->BelongsToCurrentThread());
348
349   AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
350   for (; it != output_dispatchers_.end(); ++it) {
351     scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher;
352     dispatcher->Shutdown();
353
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;
361   }
362
363   output_dispatchers_.clear();
364 }
365
366 void AudioManagerBase::AddOutputDeviceChangeListener(
367     AudioDeviceListener* listener) {
368   DCHECK(task_runner_->BelongsToCurrentThread());
369   output_listeners_.AddObserver(listener);
370 }
371
372 void AudioManagerBase::RemoveOutputDeviceChangeListener(
373     AudioDeviceListener* listener) {
374   DCHECK(task_runner_->BelongsToCurrentThread());
375   output_listeners_.RemoveObserver(listener);
376 }
377
378 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
379   DCHECK(task_runner_->BelongsToCurrentThread());
380   DVLOG(1) << "Firing OnDeviceChange() notifications.";
381   FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
382 }
383
384 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
385   return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
386       AudioParameters());
387 }
388
389 AudioParameters AudioManagerBase::GetOutputStreamParameters(
390     const std::string& device_id) {
391   return GetPreferredOutputStreamParameters(device_id,
392       AudioParameters());
393 }
394
395 AudioParameters AudioManagerBase::GetInputStreamParameters(
396     const std::string& device_id) {
397   NOTREACHED();
398   return AudioParameters();
399 }
400
401 std::string AudioManagerBase::GetAssociatedOutputDeviceID(
402     const std::string& input_device_id) {
403   NOTIMPLEMENTED();
404   return "";
405 }
406
407 std::string AudioManagerBase::GetDefaultOutputDeviceID() {
408   return "";
409 }
410
411 int AudioManagerBase::GetUserBufferSize() {
412   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
413   int buffer_size = 0;
414   std::string buffer_size_str(cmd_line->GetSwitchValueASCII(
415       switches::kAudioBufferSize));
416   if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0)
417     return buffer_size;
418
419   return 0;
420 }
421
422 scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
423     AudioLogFactory::AudioComponent component) {
424   return audio_log_factory_->CreateAudioLog(component);
425 }
426
427 void AudioManagerBase::FixWedgedAudio() {
428   DCHECK(task_runner_->BelongsToCurrentThread());
429 #if defined(OS_MACOSX)
430   // Through trial and error, we've found that one way to restore audio after a
431   // hang is to close all outstanding audio streams.  Once all streams have been
432   // closed, new streams appear to work correctly.
433   //
434   // In Chrome terms, this means we need to ask all AudioOutputDispatchers to
435   // close all Open()'d streams.  Once all streams across all dispatchers have
436   // been closed, we ask for all previously Start()'d streams to be recreated
437   // using the same AudioSourceCallback they had before.
438   //
439   // Since this operation takes place on the audio thread we can be sure that no
440   // other state-changing stream operations will take place while the fix is in
441   // progress.
442   //
443   // See http://crbug.com/160920 for additional details.
444   for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
445        it != output_dispatchers_.end(); ++it) {
446     (*it)->dispatcher->CloseStreamsForWedgeFix();
447   }
448   for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
449        it != output_dispatchers_.end(); ++it) {
450     (*it)->dispatcher->RestartStreamsForWedgeFix();
451   }
452 #endif
453 }
454
455 }  // namespace media