Home | History | Annotate | Download | only in audio
      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/message_loop/message_loop_proxy.h"
     11 #include "base/threading/thread.h"
     12 #include "build/build_config.h"
     13 #include "media/audio/audio_output_dispatcher_impl.h"
     14 #include "media/audio/audio_output_proxy.h"
     15 #include "media/audio/audio_output_resampler.h"
     16 #include "media/audio/audio_util.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"
     20 
     21 namespace media {
     22 
     23 static const int kStreamCloseDelaySeconds = 5;
     24 
     25 // Default maximum number of output streams that can be open simultaneously
     26 // for all platforms.
     27 static const int kDefaultMaxOutputStreams = 16;
     28 
     29 // Default maximum number of input streams that can be open simultaneously
     30 // for all platforms.
     31 static const int kDefaultMaxInputStreams = 16;
     32 
     33 static const int kMaxInputChannels = 2;
     34 
     35 const char AudioManagerBase::kDefaultDeviceName[] = "Default";
     36 const char AudioManagerBase::kDefaultDeviceId[] = "default";
     37 
     38 struct AudioManagerBase::DispatcherParams {
     39   DispatcherParams(const AudioParameters& input,
     40                    const AudioParameters& output,
     41                    const std::string& device_id)
     42       : input_params(input),
     43         output_params(output),
     44         input_device_id(device_id) {}
     45   ~DispatcherParams() {}
     46 
     47   const AudioParameters input_params;
     48   const AudioParameters output_params;
     49   const std::string input_device_id;
     50   scoped_refptr<AudioOutputDispatcher> dispatcher;
     51 
     52  private:
     53   DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
     54 };
     55 
     56 class AudioManagerBase::CompareByParams {
     57  public:
     58   explicit CompareByParams(const DispatcherParams* dispatcher)
     59       : dispatcher_(dispatcher) {}
     60   bool operator()(DispatcherParams* dispatcher_in) const {
     61     // We will reuse the existing dispatcher when:
     62     // 1) Unified IO is not used, input_params and output_params of the
     63     //    existing dispatcher are the same as the requested dispatcher.
     64     // 2) Unified IO is used, input_params, output_params and input_device_id
     65     //    of the existing dispatcher are the same as the request dispatcher.
     66     return (dispatcher_->input_params == dispatcher_in->input_params &&
     67             dispatcher_->output_params == dispatcher_in->output_params &&
     68             (!dispatcher_->input_params.input_channels() ||
     69              dispatcher_->input_device_id == dispatcher_in->input_device_id));
     70   }
     71 
     72  private:
     73   const DispatcherParams* dispatcher_;
     74 };
     75 
     76 AudioManagerBase::AudioManagerBase()
     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 ObserverListThreadSafe, so we don't
     82       // block the UI thread when swapping devices.
     83       output_listeners_(
     84           ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
     85       audio_thread_(new base::Thread("AudioThread")) {
     86 #if defined(OS_WIN)
     87   audio_thread_->init_com_with_mta(true);
     88 #elif defined(OS_MACOSX)
     89   // CoreAudio calls must occur on the main thread of the process, which in our
     90   // case is sadly the browser UI thread.  Failure to execute calls on the right
     91   // thread leads to crashes and odd behavior.  See http://crbug.com/158170.
     92   // TODO(dalecurtis): We should require the message loop to be passed in.
     93   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
     94   if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) &&
     95       base::MessageLoopProxy::current().get() &&
     96       base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_UI)) {
     97     message_loop_ = base::MessageLoopProxy::current();
     98     return;
     99   }
    100 #endif
    101 
    102   CHECK(audio_thread_->Start());
    103   message_loop_ = audio_thread_->message_loop_proxy();
    104 }
    105 
    106 AudioManagerBase::~AudioManagerBase() {
    107   // The platform specific AudioManager implementation must have already
    108   // stopped the audio thread. Otherwise, we may destroy audio streams before
    109   // stopping the thread, resulting an unexpected behavior.
    110   // This way we make sure activities of the audio streams are all stopped
    111   // before we destroy them.
    112   CHECK(!audio_thread_.get());
    113   // All the output streams should have been deleted.
    114   DCHECK_EQ(0, num_output_streams_);
    115   // All the input streams should have been deleted.
    116   DCHECK_EQ(0, num_input_streams_);
    117 }
    118 
    119 string16 AudioManagerBase::GetAudioInputDeviceModel() {
    120   return string16();
    121 }
    122 
    123 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() {
    124   return message_loop_;
    125 }
    126 
    127 scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() {
    128   // Lazily start the worker thread.
    129   if (!audio_thread_->IsRunning())
    130     CHECK(audio_thread_->Start());
    131 
    132   return audio_thread_->message_loop_proxy();
    133 }
    134 
    135 AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
    136     const AudioParameters& params,
    137     const std::string& input_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(message_loop_->BelongsToCurrentThread());
    141 
    142   if (!params.IsValid()) {
    143     DLOG(ERROR) << "Audio parameters are invalid";
    144     return NULL;
    145   }
    146 
    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;
    157   }
    158 
    159   AudioOutputStream* stream;
    160   switch (params.format()) {
    161     case AudioParameters::AUDIO_PCM_LINEAR:
    162       stream = MakeLinearOutputStream(params);
    163       break;
    164     case AudioParameters::AUDIO_PCM_LOW_LATENCY:
    165       stream = MakeLowLatencyOutputStream(params, input_device_id);
    166       break;
    167     case AudioParameters::AUDIO_FAKE:
    168       stream = FakeAudioOutputStream::MakeFakeStream(this, params);
    169       break;
    170     default:
    171       stream = NULL;
    172       break;
    173   }
    174 
    175   if (stream) {
    176     ++num_output_streams_;
    177   }
    178 
    179   return stream;
    180 }
    181 
    182 AudioInputStream* AudioManagerBase::MakeAudioInputStream(
    183     const AudioParameters& params, const std::string& device_id) {
    184   // TODO(miu): Fix ~20 call points across several unit test modules to call
    185   // this method on the audio thread, then uncomment the following:
    186   // DCHECK(message_loop_->BelongsToCurrentThread());
    187 
    188   if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
    189       device_id.empty()) {
    190     DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
    191     return NULL;
    192   }
    193 
    194   if (num_input_streams_ >= max_num_input_streams_) {
    195     DLOG(ERROR) << "Number of opened input audio streams "
    196                 << num_input_streams_
    197                 << " exceed the max allowed number " << max_num_input_streams_;
    198     return NULL;
    199   }
    200 
    201   AudioInputStream* stream;
    202   switch (params.format()) {
    203     case AudioParameters::AUDIO_PCM_LINEAR:
    204       stream = MakeLinearInputStream(params, device_id);
    205       break;
    206     case AudioParameters::AUDIO_PCM_LOW_LATENCY:
    207       stream = MakeLowLatencyInputStream(params, device_id);
    208       break;
    209     case AudioParameters::AUDIO_FAKE:
    210       stream = FakeAudioInputStream::MakeFakeStream(this, params);
    211       break;
    212     default:
    213       stream = NULL;
    214       break;
    215   }
    216 
    217   if (stream) {
    218     ++num_input_streams_;
    219   }
    220 
    221   return stream;
    222 }
    223 
    224 AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
    225     const AudioParameters& params, const std::string& input_device_id) {
    226 #if defined(OS_IOS)
    227   // IOS implements audio input only.
    228   NOTIMPLEMENTED();
    229   return NULL;
    230 #else
    231   DCHECK(message_loop_->BelongsToCurrentThread());
    232 
    233   // If we're not using AudioOutputResampler our output parameters are the same
    234   // as our input parameters.
    235   AudioParameters output_params = params;
    236   if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
    237     output_params = GetPreferredOutputStreamParameters(params);
    238 
    239     // Ensure we only pass on valid output parameters.
    240     if (!output_params.IsValid()) {
    241       // We've received invalid audio output parameters, so switch to a mock
    242       // output device based on the input parameters.  This may happen if the OS
    243       // provided us junk values for the hardware configuration.
    244       LOG(ERROR) << "Invalid audio output parameters received; using fake "
    245                  << "audio path. Channels: " << output_params.channels() << ", "
    246                  << "Sample Rate: " << output_params.sample_rate() << ", "
    247                  << "Bits Per Sample: " << output_params.bits_per_sample()
    248                  << ", Frames Per Buffer: "
    249                  << output_params.frames_per_buffer();
    250 
    251       // Tell the AudioManager to create a fake output device.
    252       output_params = AudioParameters(
    253           AudioParameters::AUDIO_FAKE, params.channel_layout(),
    254           params.sample_rate(), params.bits_per_sample(),
    255           params.frames_per_buffer());
    256     }
    257   }
    258 
    259   DispatcherParams* dispatcher_params =
    260       new DispatcherParams(params, output_params, input_device_id);
    261 
    262   AudioOutputDispatchers::iterator it =
    263       std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
    264                    CompareByParams(dispatcher_params));
    265   if (it != output_dispatchers_.end()) {
    266     delete dispatcher_params;
    267     return new AudioOutputProxy((*it)->dispatcher.get());
    268   }
    269 
    270   const base::TimeDelta kCloseDelay =
    271       base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
    272   scoped_refptr<AudioOutputDispatcher> dispatcher;
    273   if (output_params.format() != AudioParameters::AUDIO_FAKE) {
    274     dispatcher = new AudioOutputResampler(this, params, output_params,
    275                                           input_device_id, kCloseDelay);
    276   } else {
    277     dispatcher = new AudioOutputDispatcherImpl(this, output_params,
    278                                                input_device_id, kCloseDelay);
    279   }
    280 
    281   dispatcher_params->dispatcher = dispatcher;
    282   output_dispatchers_.push_back(dispatcher_params);
    283   return new AudioOutputProxy(dispatcher.get());
    284 #endif  // defined(OS_IOS)
    285 }
    286 
    287 void AudioManagerBase::ShowAudioInputSettings() {
    288 }
    289 
    290 void AudioManagerBase::GetAudioInputDeviceNames(
    291     media::AudioDeviceNames* device_names) {
    292 }
    293 
    294 void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
    295   DCHECK(stream);
    296   // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
    297   // For example, pass the ownership to AudioManager so it can delete the
    298   // streams.
    299   --num_output_streams_;
    300   delete stream;
    301 }
    302 
    303 void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
    304   DCHECK(stream);
    305   // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
    306   --num_input_streams_;
    307   delete stream;
    308 }
    309 
    310 void AudioManagerBase::Shutdown() {
    311   // To avoid running into deadlocks while we stop the thread, shut it down
    312   // via a local variable while not holding the audio thread lock.
    313   scoped_ptr<base::Thread> audio_thread;
    314   {
    315     base::AutoLock lock(audio_thread_lock_);
    316     audio_thread_.swap(audio_thread);
    317   }
    318 
    319   if (!audio_thread)
    320     return;
    321 
    322   // Only true when we're sharing the UI message loop with the browser.  The UI
    323   // loop is no longer running at this time and browser destruction is imminent.
    324   if (message_loop_->BelongsToCurrentThread()) {
    325     ShutdownOnAudioThread();
    326   } else {
    327     message_loop_->PostTask(FROM_HERE, base::Bind(
    328         &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
    329   }
    330 
    331   // Stop() will wait for any posted messages to be processed first.
    332   audio_thread->Stop();
    333 }
    334 
    335 void AudioManagerBase::ShutdownOnAudioThread() {
    336 // IOS implements audio input only.
    337 #if defined(OS_IOS)
    338   return;
    339 #else
    340   // This should always be running on the audio thread, but since we've cleared
    341   // the audio_thread_ member pointer when we get here, we can't verify exactly
    342   // what thread we're running on.  The method is not public though and only
    343   // called from one place, so we'll leave it at that.
    344   AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
    345   for (; it != output_dispatchers_.end(); ++it) {
    346     scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher;
    347     if (dispatcher.get()) {
    348       dispatcher->Shutdown();
    349       // All AudioOutputProxies must have been freed before Shutdown is called.
    350       // If they still exist, things will go bad.  They have direct pointers to
    351       // both physical audio stream objects that belong to the dispatcher as
    352       // well as the message loop of the audio thread that will soon go away.
    353       // So, better crash now than later.
    354       DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive";
    355       dispatcher = NULL;
    356     }
    357   }
    358 
    359   output_dispatchers_.clear();
    360 #endif  // defined(OS_IOS)
    361 }
    362 
    363 void AudioManagerBase::AddOutputDeviceChangeListener(
    364     AudioDeviceListener* listener) {
    365   DCHECK(message_loop_->BelongsToCurrentThread());
    366   output_listeners_.AddObserver(listener);
    367 }
    368 
    369 void AudioManagerBase::RemoveOutputDeviceChangeListener(
    370     AudioDeviceListener* listener) {
    371   DCHECK(message_loop_->BelongsToCurrentThread());
    372   output_listeners_.RemoveObserver(listener);
    373 }
    374 
    375 void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
    376   DCHECK(message_loop_->BelongsToCurrentThread());
    377   DVLOG(1) << "Firing OnDeviceChange() notifications.";
    378   FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
    379 }
    380 
    381 AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
    382   return GetPreferredOutputStreamParameters(AudioParameters());
    383 }
    384 
    385 AudioParameters AudioManagerBase::GetInputStreamParameters(
    386     const std::string& device_id) {
    387   NOTREACHED();
    388   return AudioParameters();
    389 }
    390 
    391 }  // namespace media
    392