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.
5 #include "content/browser/renderer_host/media/audio_input_device_manager.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"
20 const int AudioInputDeviceManager::kFakeOpenSessionId
= 1;
23 // Starting id for the first capture session.
24 const int kFirstSessionId
= AudioInputDeviceManager::kFakeOpenSessionId
+ 1;
27 AudioInputDeviceManager::AudioInputDeviceManager(
28 media::AudioManager
* audio_manager
)
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
,
39 fake_device
.session_id
= kFakeOpenSessionId
;
40 devices_
.push_back(fake_device
);
43 AudioInputDeviceManager::~AudioInputDeviceManager() {
46 const StreamDeviceInfo
* AudioInputDeviceManager::GetOpenedDeviceInfoById(
48 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
49 StreamDeviceList::iterator device
= GetDevice(session_id
);
50 if (device
== devices_
.end())
56 void AudioInputDeviceManager::Register(
57 MediaStreamProviderListener
* listener
,
58 const scoped_refptr
<base::SingleThreadTaskRunner
>& device_task_runner
) {
59 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
61 DCHECK(!device_task_runner_
);
63 device_task_runner_
= device_task_runner
;
66 void AudioInputDeviceManager::Unregister() {
71 void AudioInputDeviceManager::EnumerateDevices(MediaStreamType stream_type
) {
72 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
75 device_task_runner_
->PostTask(
77 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread
,
81 int AudioInputDeviceManager::Open(const StreamDeviceInfo
& device
) {
82 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
83 // Generate a new id for this device.
84 int session_id
= next_capture_session_id_
++;
85 device_task_runner_
->PostTask(
87 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread
,
88 this, session_id
, device
));
93 void AudioInputDeviceManager::Close(int session_id
) {
94 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
96 StreamDeviceList::iterator device
= GetDevice(session_id
);
97 if (device
== devices_
.end())
99 const MediaStreamType stream_type
= device
->device
.type
;
100 if (session_id
!= kFakeOpenSessionId
)
101 devices_
.erase(device
);
103 // Post a callback through the listener on IO thread since
104 // MediaStreamManager is expecting the callback asynchronously.
105 BrowserThread::PostTask(BrowserThread::IO
,
107 base::Bind(&AudioInputDeviceManager::ClosedOnIOThread
,
108 this, stream_type
, session_id
));
111 void AudioInputDeviceManager::UseFakeDevice() {
112 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
113 use_fake_device_
= true;
116 bool AudioInputDeviceManager::ShouldUseFakeDevice() const {
117 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
118 return use_fake_device_
;
121 void AudioInputDeviceManager::EnumerateOnDeviceThread(
122 MediaStreamType stream_type
) {
123 SCOPED_UMA_HISTOGRAM_TIMER(
124 "Media.AudioInputDeviceManager.EnumerateOnDeviceThreadTime");
125 DCHECK(IsOnDeviceThread());
127 media::AudioDeviceNames device_names
;
129 switch (stream_type
) {
130 case MEDIA_DEVICE_AUDIO_CAPTURE
:
131 // AudioManager is guaranteed to outlive MediaStreamManager in
133 audio_manager_
->GetAudioInputDeviceNames(&device_names
);
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
));
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
));
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(
162 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread
,
163 this, stream_type
, base::Passed(&devices
)));
166 void AudioInputDeviceManager::OpenOnDeviceThread(
167 int session_id
, const StreamDeviceInfo
& info
) {
168 SCOPED_UMA_HISTOGRAM_TIMER(
169 "Media.AudioInputDeviceManager.OpenOnDeviceThreadTime");
170 DCHECK(IsOnDeviceThread());
172 StreamDeviceInfo
out(info
.device
.type
, info
.device
.name
, info
.device
.id
,
174 out
.session_id
= session_id
;
176 MediaStreamDevice::AudioDeviceParameters
& input_params
= out
.device
.input
;
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
;
183 // Get the preferred sample rate and channel configuration for the
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();
192 // Add preferred output device information if a matching output device
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();
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
,
211 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread
,
212 this, session_id
, out
));
215 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread(
216 MediaStreamType stream_type
,
217 scoped_ptr
<StreamDeviceInfoArray
> devices
) {
218 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
219 // Ensure that |devices| gets deleted on exit.
221 listener_
->DevicesEnumerated(stream_type
, *devices
);
224 void AudioInputDeviceManager::OpenedOnIOThread(int session_id
,
225 const StreamDeviceInfo
& info
) {
226 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
227 DCHECK_EQ(session_id
, info
.session_id
);
228 DCHECK(GetDevice(session_id
) == devices_
.end());
230 devices_
.push_back(info
);
233 listener_
->Opened(info
.device
.type
, session_id
);
236 void AudioInputDeviceManager::ClosedOnIOThread(MediaStreamType stream_type
,
238 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
240 listener_
->Closed(stream_type
, session_id
);
243 bool AudioInputDeviceManager::IsOnDeviceThread() const {
244 return device_task_runner_
->BelongsToCurrentThread();
247 AudioInputDeviceManager::StreamDeviceList::iterator
248 AudioInputDeviceManager::GetDevice(int session_id
) {
249 for (StreamDeviceList::iterator
i(devices_
.begin()); i
!= devices_
.end();
251 if (i
->session_id
== session_id
)
255 return devices_
.end();
258 } // namespace content