Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_input_device_manager.cc
blobb4959567a3179f1db9c045dbed6f5c9a9bdd0c39
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"
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"
18 namespace content {
20 const int AudioInputDeviceManager::kFakeOpenSessionId = 1;
22 namespace {
23 // Starting id for the first capture session.
24 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1;
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, false);
38 fake_device.session_id = kFakeOpenSessionId;
39 devices_.push_back(fake_device);
42 AudioInputDeviceManager::~AudioInputDeviceManager() {
45 const StreamDeviceInfo* AudioInputDeviceManager::GetOpenedDeviceInfoById(
46 int session_id) {
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
48 StreamDeviceList::iterator device = GetDevice(session_id);
49 if (device == devices_.end())
50 return NULL;
52 return &(*device);
55 void AudioInputDeviceManager::Register(
56 MediaStreamProviderListener* listener,
57 base::MessageLoopProxy* device_thread_loop) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
59 DCHECK(!listener_);
60 DCHECK(!device_loop_.get());
61 listener_ = listener;
62 device_loop_ = device_thread_loop;
65 void AudioInputDeviceManager::Unregister() {
66 DCHECK(listener_);
67 listener_ = NULL;
70 void AudioInputDeviceManager::EnumerateDevices(MediaStreamType stream_type) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72 DCHECK(listener_);
74 device_loop_->PostTask(
75 FROM_HERE,
76 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread,
77 this, stream_type));
80 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
82 // Generate a new id for this device.
83 int session_id = next_capture_session_id_++;
84 device_loop_->PostTask(
85 FROM_HERE,
86 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread,
87 this, session_id, device));
89 return session_id;
92 void AudioInputDeviceManager::Close(int session_id) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
94 DCHECK(listener_);
95 StreamDeviceList::iterator device = GetDevice(session_id);
96 if (device == devices_.end())
97 return;
98 const MediaStreamType stream_type = device->device.type;
99 if (session_id != kFakeOpenSessionId)
100 devices_.erase(device);
102 // Post a callback through the listener on IO thread since
103 // MediaStreamManager is expecting the callback asynchronously.
104 BrowserThread::PostTask(BrowserThread::IO,
105 FROM_HERE,
106 base::Bind(&AudioInputDeviceManager::ClosedOnIOThread,
107 this, stream_type, session_id));
110 void AudioInputDeviceManager::UseFakeDevice() {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
112 use_fake_device_ = true;
115 bool AudioInputDeviceManager::ShouldUseFakeDevice() const {
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
117 return use_fake_device_;
120 void AudioInputDeviceManager::EnumerateOnDeviceThread(
121 MediaStreamType stream_type) {
122 SCOPED_UMA_HISTOGRAM_TIMER(
123 "Media.AudioInputDeviceManager.EnumerateOnDeviceThreadTime");
124 DCHECK(IsOnDeviceThread());
126 media::AudioDeviceNames device_names;
128 switch (stream_type) {
129 case MEDIA_DEVICE_AUDIO_CAPTURE:
130 // AudioManager is guaranteed to outlive MediaStreamManager in
131 // BrowserMainloop.
132 audio_manager_->GetAudioInputDeviceNames(&device_names);
133 break;
135 default:
136 NOTREACHED();
137 break;
140 scoped_ptr<StreamDeviceInfoArray> devices(new StreamDeviceInfoArray());
141 for (media::AudioDeviceNames::iterator it = device_names.begin();
142 it != device_names.end(); ++it) {
143 // Add device information to device vector.
144 devices->push_back(StreamDeviceInfo(
145 stream_type, it->device_name, it->unique_id, false));
148 // If the |use_fake_device_| flag is on, inject the fake device if there is
149 // no available device on the OS.
150 if (use_fake_device_ && devices->empty()) {
151 devices->push_back(StreamDeviceInfo(
152 stream_type, media::AudioManagerBase::kDefaultDeviceName,
153 media::AudioManagerBase::kDefaultDeviceId, false));
156 // Return the device list through the listener by posting a task on
157 // IO thread since MediaStreamManager handles the callback asynchronously.
158 BrowserThread::PostTask(
159 BrowserThread::IO,
160 FROM_HERE,
161 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread,
162 this, stream_type, base::Passed(&devices)));
165 void AudioInputDeviceManager::OpenOnDeviceThread(
166 int session_id, const StreamDeviceInfo& info) {
167 SCOPED_UMA_HISTOGRAM_TIMER(
168 "Media.AudioInputDeviceManager.OpenOnDeviceThreadTime");
169 DCHECK(IsOnDeviceThread());
171 StreamDeviceInfo out(info.device.type, info.device.name, info.device.id,
172 0, 0, false);
173 out.session_id = session_id;
174 if (use_fake_device_) {
175 // Don't need to query the hardware information if using fake device.
176 out.device.sample_rate = 44100;
177 out.device.channel_layout = media::CHANNEL_LAYOUT_STEREO;
178 } else {
179 // Get the preferred sample rate and channel configuration for the
180 // audio device.
181 media::AudioParameters params =
182 audio_manager_->GetInputStreamParameters(info.device.id);
183 out.device.sample_rate = params.sample_rate();
184 out.device.channel_layout = params.channel_layout();
187 // Return the |session_id| through the listener by posting a task on
188 // IO thread since MediaStreamManager handles the callback asynchronously.
189 BrowserThread::PostTask(BrowserThread::IO,
190 FROM_HERE,
191 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread,
192 this, session_id, out));
195 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread(
196 MediaStreamType stream_type,
197 scoped_ptr<StreamDeviceInfoArray> devices) {
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
199 // Ensure that |devices| gets deleted on exit.
200 if (listener_)
201 listener_->DevicesEnumerated(stream_type, *devices);
204 void AudioInputDeviceManager::OpenedOnIOThread(int session_id,
205 const StreamDeviceInfo& info) {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
207 DCHECK_EQ(session_id, info.session_id);
208 DCHECK(GetDevice(session_id) == devices_.end());
209 devices_.push_back(info);
211 if (listener_)
212 listener_->Opened(info.device.type, session_id);
215 void AudioInputDeviceManager::ClosedOnIOThread(MediaStreamType stream_type,
216 int session_id) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
218 if (listener_)
219 listener_->Closed(stream_type, session_id);
222 bool AudioInputDeviceManager::IsOnDeviceThread() const {
223 return device_loop_->BelongsToCurrentThread();
226 AudioInputDeviceManager::StreamDeviceList::iterator
227 AudioInputDeviceManager::GetDevice(int session_id) {
228 for (StreamDeviceList::iterator i(devices_.begin()); i != devices_.end();
229 ++i) {
230 if (i->session_id == session_id)
231 return i;
234 return devices_.end();
237 } // namespace content