OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 5 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "content/browser/renderer_host/media/audio_input_device_manager_event_h
andler.h" | 9 #include "content/browser/renderer_host/media/audio_input_device_manager_event_h
andler.h" |
10 #include "content/public/browser/browser_thread.h" | 10 #include "content/public/browser/browser_thread.h" |
11 #include "media/audio/audio_manager_base.h" | 11 #include "media/audio/audio_manager_base.h" |
12 | 12 |
13 using content::BrowserThread; | 13 using content::BrowserThread; |
14 | 14 |
15 namespace media_stream { | 15 namespace media_stream { |
16 | 16 |
17 const int AudioInputDeviceManager::kFakeOpenSessionId = 1; | 17 const int AudioInputDeviceManager::kFakeOpenSessionId = 1; |
18 const int AudioInputDeviceManager::kInvalidSessionId = 0; | 18 const int AudioInputDeviceManager::kInvalidSessionId = 0; |
19 const char AudioInputDeviceManager::kInvalidDeviceId[] = ""; | 19 const char AudioInputDeviceManager::kInvalidDeviceId[] = ""; |
20 | 20 |
21 // Starting id for the first capture session. | 21 // Starting id for the first capture session. |
22 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1; | 22 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1; |
23 | 23 |
24 // Helper function. | |
25 static bool IsValidAudioInputDevice(const media::AudioDeviceName& device) { | |
26 AudioManager* audio_manager = AudioManager::GetAudioManager(); | |
27 if (!audio_manager) | |
28 return false; | |
29 | |
30 // Get the up-to-date list of devices and verify the device is in the list. | |
31 media::AudioDeviceNames device_names; | |
32 audio_manager->GetAudioInputDeviceNames(&device_names); | |
33 if (!device_names.empty()) { | |
34 for (media::AudioDeviceNames::iterator iter = device_names.begin(); | |
35 iter != device_names.end(); | |
36 ++iter) { | |
37 if (iter->device_name == device.device_name && | |
38 iter->unique_id == device.unique_id) | |
39 return true; | |
40 } | |
41 } | |
42 // The device wasn't found. | |
43 return false; | |
44 } | |
45 | |
46 AudioInputDeviceManager::AudioInputDeviceManager() | 24 AudioInputDeviceManager::AudioInputDeviceManager() |
47 : audio_input_device_thread_("AudioInputDeviceManagerThread"), | 25 : listener_(NULL), |
48 listener_(NULL), | |
49 next_capture_session_id_(kFirstSessionId) { | 26 next_capture_session_id_(kFirstSessionId) { |
50 audio_input_device_thread_.Start(); | |
51 } | 27 } |
52 | 28 |
53 AudioInputDeviceManager::~AudioInputDeviceManager() { | 29 AudioInputDeviceManager::~AudioInputDeviceManager() { |
54 audio_input_device_thread_.Stop(); | |
55 } | 30 } |
56 | 31 |
57 void AudioInputDeviceManager::Register(MediaStreamProviderListener* listener) { | 32 void AudioInputDeviceManager::Register(MediaStreamProviderListener* listener) { |
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
59 DCHECK(!listener_); | 34 DCHECK(!listener_); |
60 listener_ = listener; | 35 listener_ = listener; |
61 } | 36 } |
62 | 37 |
63 void AudioInputDeviceManager::Unregister() { | 38 void AudioInputDeviceManager::Unregister() { |
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
65 DCHECK(listener_); | 40 DCHECK(listener_); |
66 listener_ = NULL; | 41 listener_ = NULL; |
67 } | 42 } |
68 | 43 |
69 void AudioInputDeviceManager::EnumerateDevices() { | 44 void AudioInputDeviceManager::EnumerateDevices() { |
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
71 DCHECK(listener_); | 46 DCHECK(listener_); |
72 | 47 |
73 audio_input_device_thread_.message_loop()->PostTask( | 48 media::AudioDeviceNames device_names; |
| 49 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); |
| 50 |
| 51 StreamDeviceInfoArray* devices = new StreamDeviceInfoArray; |
| 52 for (media::AudioDeviceNames::iterator it = device_names.begin(); |
| 53 it != device_names.end(); |
| 54 ++it) { |
| 55 devices->push_back(StreamDeviceInfo(kAudioCapture, it->device_name, |
| 56 it->unique_id, false)); |
| 57 } |
| 58 |
| 59 // Returns the device list through the listener by posting a task on |
| 60 // IO thread since MediaStreamManager handles the callback asynchronously. |
| 61 BrowserThread::PostTask( |
| 62 BrowserThread::IO, |
74 FROM_HERE, | 63 FROM_HERE, |
75 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread, | 64 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread, |
76 base::Unretained(this))); | 65 base::Unretained(this), |
| 66 devices)); |
77 } | 67 } |
78 | 68 |
79 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { | 69 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { |
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
81 | 71 |
82 // Generate a new id for this device. | 72 // Generates a new id for this device. |
83 int audio_input_session_id = next_capture_session_id_++; | 73 int session_id = next_capture_session_id_++; |
| 74 DCHECK(devices_.find(session_id) == devices_.end()); |
84 | 75 |
85 audio_input_device_thread_.message_loop()->PostTask( | 76 media::AudioDeviceName audio_input_device_name; |
86 FROM_HERE, | 77 audio_input_device_name.device_name = device.name; |
87 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread, | 78 audio_input_device_name.unique_id = device.device_id; |
88 base::Unretained(this), audio_input_session_id, device)); | |
89 | 79 |
90 return audio_input_session_id; | 80 // Adds the session_id and device to the list. |
| 81 devices_[session_id] = audio_input_device_name; |
| 82 |
| 83 // Returns the |session_id| through the listener by posting a task on |
| 84 // IO thread since MediaStreamManager handles the callback asynchronously. |
| 85 BrowserThread::PostTask(BrowserThread::IO, |
| 86 FROM_HERE, |
| 87 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread, |
| 88 base::Unretained(this), |
| 89 session_id)); |
| 90 |
| 91 return session_id; |
91 } | 92 } |
92 | 93 |
93 void AudioInputDeviceManager::Close(int session_id) { | 94 void AudioInputDeviceManager::Close(int session_id) { |
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
95 DCHECK(listener_); | 96 DCHECK(listener_); |
96 | 97 |
97 audio_input_device_thread_.message_loop()->PostTask( | 98 if (devices_.find(session_id) != devices_.end()) |
98 FROM_HERE, | 99 devices_.erase(session_id); |
99 base::Bind(&AudioInputDeviceManager::CloseOnDeviceThread, | 100 |
100 base::Unretained(this), session_id)); | 101 // Checks if the device has been stopped, if not, send stop signal. |
| 102 EventHandlerMap::iterator it = event_handlers_.find(session_id); |
| 103 if (it != event_handlers_.end()) { |
| 104 it->second->OnDeviceStopped(session_id); |
| 105 event_handlers_.erase(session_id); |
| 106 } |
| 107 |
| 108 // Posts a callback through the listener on IO thread since |
| 109 // MediaStreamManager handles the callback asynchronously. |
| 110 BrowserThread::PostTask(BrowserThread::IO, |
| 111 FROM_HERE, |
| 112 base::Bind(&AudioInputDeviceManager::ClosedOnIOThread, |
| 113 base::Unretained(this), |
| 114 session_id)); |
101 } | 115 } |
102 | 116 |
103 void AudioInputDeviceManager::Start( | 117 void AudioInputDeviceManager::Start( |
104 int session_id, AudioInputDeviceManagerEventHandler* event_handler) { | 118 int session_id, AudioInputDeviceManagerEventHandler* event_handler) { |
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
106 DCHECK(event_handler); | 120 DCHECK(event_handler); |
107 | 121 |
108 // Solution for not using MediaStreamManager. This is needed when Start() is | 122 // Solution for not using MediaStreamManager. This is needed when Start() is |
109 // called without using Open(), we post default device for test purpose. | 123 // called without using Open(), we post default device for test purpose. |
110 // And we do not store the info for the kFakeOpenSessionId but return | 124 // And we do not store the info for the kFakeOpenSessionId but return |
111 // the callback immediately. | 125 // the callback immediately. |
112 if (session_id == kFakeOpenSessionId) { | 126 if (session_id == kFakeOpenSessionId) { |
113 event_handler->OnDeviceStarted(session_id, | 127 event_handler->OnDeviceStarted(session_id, |
114 AudioManagerBase::kDefaultDeviceId); | 128 AudioManagerBase::kDefaultDeviceId); |
115 return; | 129 return; |
116 } | 130 } |
117 | 131 |
118 // If session has been started, post a callback with an error. | 132 // Checks if the device has been opened or not. |
119 if (event_handlers_.find(session_id) != event_handlers_.end()) { | 133 std::string device_id = (devices_.find(session_id) == devices_.end()) ? |
120 // Session has been started, post a callback with error. | 134 kInvalidDeviceId : devices_[session_id].unique_id; |
121 event_handler->OnDeviceStarted(session_id, kInvalidDeviceId); | |
122 return; | |
123 } | |
124 | 135 |
125 // Add the event handler to the session. | 136 // Adds the event handler to the session if the session has not been started, |
126 event_handlers_.insert(std::make_pair(session_id, event_handler)); | 137 // otherwise post a |kInvalidDeviceId| to indicate that Start() fails. |
| 138 if (event_handlers_.find(session_id) == event_handlers_.end()) |
| 139 event_handlers_.insert(std::make_pair(session_id, event_handler)); |
| 140 else |
| 141 device_id = kInvalidDeviceId; |
127 | 142 |
128 audio_input_device_thread_.message_loop()->PostTask( | 143 // Posts a callback through the AudioInputRendererHost to notify the renderer |
129 FROM_HERE, | 144 // that the device has started. |
130 base::Bind(&AudioInputDeviceManager::StartOnDeviceThread, | 145 event_handler->OnDeviceStarted(session_id, device_id); |
131 base::Unretained(this), session_id)); | |
132 } | 146 } |
133 | 147 |
134 void AudioInputDeviceManager::Stop(int session_id) { | 148 void AudioInputDeviceManager::Stop(int session_id) { |
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
136 | 150 |
137 audio_input_device_thread_.message_loop()->PostTask( | 151 // Erases the event handler referenced by the session_id. |
138 FROM_HERE, | 152 event_handlers_.erase(session_id); |
139 base::Bind(&AudioInputDeviceManager::StopOnDeviceThread, | |
140 base::Unretained(this), session_id)); | |
141 } | |
142 | |
143 void AudioInputDeviceManager::EnumerateOnDeviceThread() { | |
144 DCHECK(IsOnCaptureDeviceThread()); | |
145 | |
146 // Get the device list from system. | |
147 media::AudioDeviceNames device_names; | |
148 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); | |
149 | |
150 StreamDeviceInfoArray devices; | |
151 for (media::AudioDeviceNames::iterator it = device_names.begin(); | |
152 it != device_names.end(); | |
153 ++it) { | |
154 devices.push_back(StreamDeviceInfo(kAudioCapture, it->device_name, | |
155 it->unique_id, false)); | |
156 } | |
157 | |
158 BrowserThread::PostTask( | |
159 BrowserThread::IO, | |
160 FROM_HERE, | |
161 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread, | |
162 base::Unretained(this), devices)); | |
163 } | |
164 | |
165 void AudioInputDeviceManager::OpenOnDeviceThread( | |
166 int session_id, const StreamDeviceInfo& device) { | |
167 DCHECK(IsOnCaptureDeviceThread()); | |
168 DCHECK(devices_.find(session_id) == devices_.end()); | |
169 | |
170 media::AudioDeviceName audio_input_device_name; | |
171 audio_input_device_name.device_name = device.name; | |
172 audio_input_device_name.unique_id = device.device_id; | |
173 | |
174 // Check if the device is valid | |
175 if (!IsValidAudioInputDevice(audio_input_device_name)) { | |
176 SignalError(session_id, kDeviceNotAvailable); | |
177 return; | |
178 } | |
179 | |
180 // Add the session_id and device to the list. | |
181 devices_[session_id] = audio_input_device_name; | |
182 BrowserThread::PostTask(BrowserThread::IO, | |
183 FROM_HERE, | |
184 base::Bind( | |
185 &AudioInputDeviceManager::OpenedOnIOThread, | |
186 base::Unretained(this), | |
187 session_id)); | |
188 } | |
189 | |
190 void AudioInputDeviceManager::CloseOnDeviceThread(int session_id) { | |
191 DCHECK(IsOnCaptureDeviceThread()); | |
192 DCHECK(devices_.find(session_id) != devices_.end()); | |
193 | |
194 devices_.erase(session_id); | |
195 BrowserThread::PostTask(BrowserThread::IO, | |
196 FROM_HERE, | |
197 base::Bind( | |
198 &AudioInputDeviceManager::ClosedOnIOThread, | |
199 base::Unretained(this), | |
200 session_id)); | |
201 } | |
202 | |
203 void AudioInputDeviceManager::StartOnDeviceThread(const int session_id) { | |
204 DCHECK(IsOnCaptureDeviceThread()); | |
205 | |
206 // Get the up-to-date device enumeration list from the OS and find out | |
207 // the unique id of the device. | |
208 std::string device_id = kInvalidDeviceId; | |
209 AudioInputDeviceMap::const_iterator it = devices_.find(session_id); | |
210 if (it != devices_.end()) { | |
211 media::AudioDeviceNames device_names; | |
212 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); | |
213 if (!device_names.empty()) { | |
214 int index = 0; | |
215 for (media::AudioDeviceNames::iterator iter = device_names.begin(); | |
216 iter != device_names.end(); | |
217 ++iter, ++index) { | |
218 if (iter->device_name == it->second.device_name && | |
219 iter->unique_id == it->second.unique_id) { | |
220 // Found the device. | |
221 device_id = iter->unique_id; | |
222 break; | |
223 } | |
224 } | |
225 } | |
226 } | |
227 | |
228 // Posts the index to AudioInputRenderHost through the event handler. | |
229 BrowserThread::PostTask(BrowserThread::IO, | |
230 FROM_HERE, | |
231 base::Bind( | |
232 &AudioInputDeviceManager::StartedOnIOThread, | |
233 base::Unretained(this), | |
234 session_id, | |
235 device_id)); | |
236 } | |
237 | |
238 void AudioInputDeviceManager::StopOnDeviceThread(int session_id) { | |
239 DCHECK(IsOnCaptureDeviceThread()); | |
240 BrowserThread::PostTask(BrowserThread::IO, | |
241 FROM_HERE, | |
242 base::Bind( | |
243 &AudioInputDeviceManager::StoppedOnIOThread, | |
244 base::Unretained(this), | |
245 session_id)); | |
246 } | 153 } |
247 | 154 |
248 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( | 155 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( |
249 const StreamDeviceInfoArray& devices) { | 156 StreamDeviceInfoArray* devices) { |
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 158 // Ensures that |devices| gets deleted on exit. |
| 159 scoped_ptr<StreamDeviceInfoArray> devices_array(devices); |
251 if (listener_) | 160 if (listener_) |
252 listener_->DevicesEnumerated(kAudioCapture, devices); | 161 listener_->DevicesEnumerated(kAudioCapture, *devices_array); |
253 } | 162 } |
254 | 163 |
255 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) { | 164 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) { |
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
257 if (listener_) | 166 if (listener_) |
258 listener_->Opened(kAudioCapture, session_id); | 167 listener_->Opened(kAudioCapture, session_id); |
259 } | 168 } |
260 | 169 |
261 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { | 170 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { |
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
263 EventHandlerMap::iterator it = event_handlers_.find(session_id); | |
264 if (it != event_handlers_.end()) { | |
265 // The device hasn't been stopped, send stop signal. | |
266 it->second->OnDeviceStopped(session_id); | |
267 event_handlers_.erase(session_id); | |
268 } | |
269 listener_->Closed(kAudioCapture, session_id); | |
270 } | |
271 | |
272 | |
273 void AudioInputDeviceManager::ErrorOnIOThread(int session_id, | |
274 MediaStreamProviderError error) { | |
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
276 if (listener_) | 172 if (listener_) |
277 listener_->Error(kAudioCapture, session_id, error); | 173 listener_->Closed(kAudioCapture, session_id); |
278 } | |
279 | |
280 void AudioInputDeviceManager::StartedOnIOThread( | |
281 int session_id, const std::string& device_id) { | |
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
283 | |
284 EventHandlerMap::iterator it = event_handlers_.find(session_id); | |
285 if (it == event_handlers_.end()) | |
286 return; | |
287 | |
288 // Post a callback through the AudioInputRendererHost to notify the renderer | |
289 // device has been started. | |
290 it->second->OnDeviceStarted(session_id, device_id); | |
291 } | |
292 | |
293 void AudioInputDeviceManager::StoppedOnIOThread(int session_id) { | |
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
295 // Erase the event handler referenced by the session_id. | |
296 event_handlers_.erase(session_id); | |
297 } | |
298 | |
299 void AudioInputDeviceManager::SignalError(int session_id, | |
300 MediaStreamProviderError error) { | |
301 BrowserThread::PostTask(BrowserThread::IO, | |
302 FROM_HERE, | |
303 base::Bind( | |
304 &AudioInputDeviceManager::ErrorOnIOThread, | |
305 base::Unretained(this), | |
306 session_id, | |
307 error)); | |
308 } | |
309 | |
310 bool AudioInputDeviceManager::IsOnCaptureDeviceThread() const { | |
311 return MessageLoop::current() == audio_input_device_thread_.message_loop(); | |
312 } | |
313 | |
314 void AudioInputDeviceManager::UnregisterEventHandler(int session_id) { | |
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
316 event_handlers_.erase(session_id); | |
317 } | |
318 | |
319 bool AudioInputDeviceManager::HasEventHandler(int session_id) { | |
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
321 return event_handlers_.find(session_id) != event_handlers_.end(); | |
322 } | |
323 | |
324 MessageLoop* AudioInputDeviceManager::message_loop() { | |
325 return audio_input_device_thread_.message_loop(); | |
326 } | 174 } |
327 | 175 |
328 } // namespace media_stream | 176 } // namespace media_stream |
OLD | NEW |