• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AudioInputDeviceManager(media::AudioManager * audio_manager)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 
~AudioInputDeviceManager()34 AudioInputDeviceManager::~AudioInputDeviceManager() {
35 }
36 
GetOpenedDeviceInfoById(int session_id)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 
Register(MediaStreamProviderListener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & device_task_runner)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 
Unregister()57 void AudioInputDeviceManager::Unregister() {
58   DCHECK(listener_);
59   listener_ = NULL;
60 }
61 
EnumerateDevices(MediaStreamType stream_type)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 
Open(const StreamDeviceInfo & device)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 
Close(int session_id)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 
UseFakeDevice()102 void AudioInputDeviceManager::UseFakeDevice() {
103   DCHECK_CURRENTLY_ON(BrowserThread::IO);
104   use_fake_device_ = true;
105 }
106 
ShouldUseFakeDevice() const107 bool AudioInputDeviceManager::ShouldUseFakeDevice() const {
108   DCHECK_CURRENTLY_ON(BrowserThread::IO);
109   return use_fake_device_;
110 }
111 
EnumerateOnDeviceThread(MediaStreamType stream_type)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 
OpenOnDeviceThread(int session_id,const StreamDeviceInfo & info)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 
DevicesEnumeratedOnIOThread(MediaStreamType stream_type,scoped_ptr<StreamDeviceInfoArray> devices)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 
OpenedOnIOThread(int session_id,const StreamDeviceInfo & info)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 
ClosedOnIOThread(MediaStreamType stream_type,int session_id)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 
IsOnDeviceThread() const224 bool AudioInputDeviceManager::IsOnDeviceThread() const {
225   return device_task_runner_->BelongsToCurrentThread();
226 }
227 
228 AudioInputDeviceManager::StreamDeviceList::iterator
GetDevice(int session_id)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 
GetFakeDeviceNames(media::AudioDeviceNames * device_names)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