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