Home | History | Annotate | Download | only in media
      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 "content/browser/renderer_host/media/audio_input_device_manager.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "content/public/browser/browser_thread.h"
     10 #include "content/public/common/media_stream_request.h"
     11 #include "media/audio/audio_device_name.h"
     12 #include "media/audio/audio_input_ipc.h"
     13 #include "media/audio/audio_manager_base.h"
     14 #include "media/audio/audio_parameters.h"
     15 #include "media/base/channel_layout.h"
     16 #include "media/base/scoped_histogram_timer.h"
     17 
     18 namespace content {
     19 
     20 const int AudioInputDeviceManager::kFakeOpenSessionId = 1;
     21 
     22 namespace {
     23 // Starting id for the first capture session.
     24 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1;
     25 }
     26 
     27 AudioInputDeviceManager::AudioInputDeviceManager(
     28     media::AudioManager* audio_manager)
     29     : listener_(NULL),
     30       next_capture_session_id_(kFirstSessionId),
     31       use_fake_device_(false),
     32       audio_manager_(audio_manager) {
     33   // TODO(xians): Remove this fake_device after the unittests do not need it.
     34   StreamDeviceInfo fake_device(MEDIA_DEVICE_AUDIO_CAPTURE,
     35                                media::AudioManagerBase::kDefaultDeviceName,
     36                                media::AudioManagerBase::kDefaultDeviceId,
     37                                44100, media::CHANNEL_LAYOUT_STEREO,
     38                                0);
     39   fake_device.session_id = kFakeOpenSessionId;
     40   devices_.push_back(fake_device);
     41 }
     42 
     43 AudioInputDeviceManager::~AudioInputDeviceManager() {
     44 }
     45 
     46 const StreamDeviceInfo* AudioInputDeviceManager::GetOpenedDeviceInfoById(
     47     int session_id) {
     48   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     49   StreamDeviceList::iterator device = GetDevice(session_id);
     50   if (device == devices_.end())
     51     return NULL;
     52 
     53   return &(*device);
     54 }
     55 
     56 void AudioInputDeviceManager::Register(
     57     MediaStreamProviderListener* listener,
     58     base::MessageLoopProxy* device_thread_loop) {
     59   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     60   DCHECK(!listener_);
     61   DCHECK(!device_loop_.get());
     62   listener_ = listener;
     63   device_loop_ = device_thread_loop;
     64 }
     65 
     66 void AudioInputDeviceManager::Unregister() {
     67   DCHECK(listener_);
     68   listener_ = NULL;
     69 }
     70 
     71 void AudioInputDeviceManager::EnumerateDevices(MediaStreamType stream_type) {
     72   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     73   DCHECK(listener_);
     74 
     75   device_loop_->PostTask(
     76       FROM_HERE,
     77       base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread,
     78                  this, stream_type));
     79 }
     80 
     81 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) {
     82   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     83   // Generate a new id for this device.
     84   int session_id = next_capture_session_id_++;
     85   device_loop_->PostTask(
     86       FROM_HERE,
     87       base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread,
     88                  this, session_id, device));
     89 
     90   return session_id;
     91 }
     92 
     93 void AudioInputDeviceManager::Close(int session_id) {
     94   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     95   DCHECK(listener_);
     96   StreamDeviceList::iterator device = GetDevice(session_id);
     97   if (device == devices_.end())
     98     return;
     99   const MediaStreamType stream_type = device->device.type;
    100   if (session_id != kFakeOpenSessionId)
    101     devices_.erase(device);
    102 
    103   // Post a callback through the listener on IO thread since
    104   // MediaStreamManager is expecting the callback asynchronously.
    105   BrowserThread::PostTask(BrowserThread::IO,
    106                           FROM_HERE,
    107                           base::Bind(&AudioInputDeviceManager::ClosedOnIOThread,
    108                                      this, stream_type, session_id));
    109 }
    110 
    111 void AudioInputDeviceManager::UseFakeDevice() {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    113   use_fake_device_ = true;
    114 }
    115 
    116 bool AudioInputDeviceManager::ShouldUseFakeDevice() const {
    117   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    118   return use_fake_device_;
    119 }
    120 
    121 void AudioInputDeviceManager::EnumerateOnDeviceThread(
    122     MediaStreamType stream_type) {
    123   SCOPED_UMA_HISTOGRAM_TIMER(
    124       "Media.AudioInputDeviceManager.EnumerateOnDeviceThreadTime");
    125   DCHECK(IsOnDeviceThread());
    126 
    127   media::AudioDeviceNames device_names;
    128 
    129   switch (stream_type) {
    130     case MEDIA_DEVICE_AUDIO_CAPTURE:
    131       // AudioManager is guaranteed to outlive MediaStreamManager in
    132       // BrowserMainloop.
    133       audio_manager_->GetAudioInputDeviceNames(&device_names);
    134       break;
    135 
    136     default:
    137       NOTREACHED();
    138       break;
    139   }
    140 
    141   scoped_ptr<StreamDeviceInfoArray> devices(new StreamDeviceInfoArray());
    142   for (media::AudioDeviceNames::iterator it = device_names.begin();
    143        it != device_names.end(); ++it) {
    144     // Add device information to device vector.
    145     devices->push_back(StreamDeviceInfo(
    146         stream_type, it->device_name, it->unique_id));
    147   }
    148 
    149   // If the |use_fake_device_| flag is on, inject the fake device if there is
    150   // no available device on the OS.
    151   if (use_fake_device_ && devices->empty()) {
    152     devices->push_back(StreamDeviceInfo(
    153         stream_type, media::AudioManagerBase::kDefaultDeviceName,
    154         media::AudioManagerBase::kDefaultDeviceId));
    155   }
    156 
    157   // Return the device list through the listener by posting a task on
    158   // IO thread since MediaStreamManager handles the callback asynchronously.
    159   BrowserThread::PostTask(
    160       BrowserThread::IO,
    161       FROM_HERE,
    162       base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread,
    163                  this, stream_type, base::Passed(&devices)));
    164 }
    165 
    166 void AudioInputDeviceManager::OpenOnDeviceThread(
    167     int session_id, const StreamDeviceInfo& info) {
    168   SCOPED_UMA_HISTOGRAM_TIMER(
    169       "Media.AudioInputDeviceManager.OpenOnDeviceThreadTime");
    170   DCHECK(IsOnDeviceThread());
    171 
    172   StreamDeviceInfo out(info.device.type, info.device.name, info.device.id,
    173                        0, 0, 0);
    174   out.session_id = session_id;
    175 
    176   MediaStreamDevice::AudioDeviceParameters& input_params = out.device.input;
    177 
    178   if (use_fake_device_) {
    179     // Don't need to query the hardware information if using fake device.
    180     input_params.sample_rate = 44100;
    181     input_params.channel_layout = media::CHANNEL_LAYOUT_STEREO;
    182   } else {
    183     // Get the preferred sample rate and channel configuration for the
    184     // audio device.
    185     media::AudioParameters params =
    186         audio_manager_->GetInputStreamParameters(info.device.id);
    187     input_params.sample_rate = params.sample_rate();
    188     input_params.channel_layout = params.channel_layout();
    189     input_params.frames_per_buffer = params.frames_per_buffer();
    190     input_params.effects = params.effects();
    191 
    192     // Add preferred output device information if a matching output device
    193     // exists.
    194     out.device.matched_output_device_id =
    195         audio_manager_->GetAssociatedOutputDeviceID(info.device.id);
    196     if (!out.device.matched_output_device_id.empty()) {
    197       params = audio_manager_->GetOutputStreamParameters(
    198           out.device.matched_output_device_id);
    199       MediaStreamDevice::AudioDeviceParameters& matched_output_params =
    200           out.device.matched_output;
    201       matched_output_params.sample_rate = params.sample_rate();
    202       matched_output_params.channel_layout = params.channel_layout();
    203       matched_output_params.frames_per_buffer = params.frames_per_buffer();
    204     }
    205   }
    206 
    207   // Return the |session_id| through the listener by posting a task on
    208   // IO thread since MediaStreamManager handles the callback asynchronously.
    209   BrowserThread::PostTask(BrowserThread::IO,
    210                           FROM_HERE,
    211                           base::Bind(&AudioInputDeviceManager::OpenedOnIOThread,
    212                                      this, session_id, out));
    213 }
    214 
    215 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread(
    216     MediaStreamType stream_type,
    217     scoped_ptr<StreamDeviceInfoArray> devices) {
    218   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    219   // Ensure that |devices| gets deleted on exit.
    220   if (listener_)
    221     listener_->DevicesEnumerated(stream_type, *devices);
    222 }
    223 
    224 void AudioInputDeviceManager::OpenedOnIOThread(int session_id,
    225                                                const StreamDeviceInfo& info) {
    226   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    227   DCHECK_EQ(session_id, info.session_id);
    228   DCHECK(GetDevice(session_id) == devices_.end());
    229 
    230   devices_.push_back(info);
    231 
    232   if (listener_)
    233     listener_->Opened(info.device.type, session_id);
    234 }
    235 
    236 void AudioInputDeviceManager::ClosedOnIOThread(MediaStreamType stream_type,
    237                                                int session_id) {
    238   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    239   if (listener_)
    240     listener_->Closed(stream_type, session_id);
    241 }
    242 
    243 bool AudioInputDeviceManager::IsOnDeviceThread() const {
    244   return device_loop_->BelongsToCurrentThread();
    245 }
    246 
    247 AudioInputDeviceManager::StreamDeviceList::iterator
    248 AudioInputDeviceManager::GetDevice(int session_id) {
    249   for (StreamDeviceList::iterator i(devices_.begin()); i != devices_.end();
    250        ++i) {
    251     if (i->session_id == session_id)
    252       return i;
    253   }
    254 
    255   return devices_.end();
    256 }
    257 
    258 }  // namespace content
    259