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