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( | |
74 FROM_HERE, | |
75 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread, | |
76 base::Unretained(this))); | |
77 } | |
78 | |
79 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { | |
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
81 | |
82 // Generate a new id for this device. | |
83 int audio_input_session_id = next_capture_session_id_++; | |
84 | |
85 audio_input_device_thread_.message_loop()->PostTask( | |
86 FROM_HERE, | |
87 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread, | |
88 base::Unretained(this), audio_input_session_id, device)); | |
89 | |
90 return audio_input_session_id; | |
91 } | |
92 | |
93 void AudioInputDeviceManager::Close(int session_id) { | |
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
95 DCHECK(listener_); | |
96 | |
97 audio_input_device_thread_.message_loop()->PostTask( | |
98 FROM_HERE, | |
99 base::Bind(&AudioInputDeviceManager::CloseOnDeviceThread, | |
100 base::Unretained(this), session_id)); | |
101 } | |
102 | |
103 void AudioInputDeviceManager::Start( | |
104 int session_id, AudioInputDeviceManagerEventHandler* event_handler) { | |
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
106 DCHECK(event_handler); | |
107 | |
108 // Solution for not using MediaStreamManager. This is needed when Start() is | |
109 // called without using Open(), we post default device for test purpose. | |
110 // And we do not store the info for the kFakeOpenSessionId but return | |
111 // the callback immediately. | |
112 if (session_id == kFakeOpenSessionId) { | |
113 event_handler->OnDeviceStarted(session_id, | |
114 AudioManagerBase::kDefaultDeviceId); | |
115 return; | |
116 } | |
117 | |
118 // If session has been started, post a callback with an error. | |
119 if (event_handlers_.find(session_id) != event_handlers_.end()) { | |
120 // Session has been started, post a callback with error. | |
121 event_handler->OnDeviceStarted(session_id, kInvalidDeviceId); | |
122 return; | |
123 } | |
124 | |
125 // Add the event handler to the session. | |
126 event_handlers_.insert(std::make_pair(session_id, event_handler)); | |
127 | |
128 audio_input_device_thread_.message_loop()->PostTask( | |
129 FROM_HERE, | |
130 base::Bind(&AudioInputDeviceManager::StartOnDeviceThread, | |
131 base::Unretained(this), session_id)); | |
132 } | |
133 | |
134 void AudioInputDeviceManager::Stop(int session_id) { | |
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
136 | |
137 audio_input_device_thread_.message_loop()->PostTask( | |
138 FROM_HERE, | |
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. | 48 // Get the device list from system. |
147 media::AudioDeviceNames device_names; | 49 media::AudioDeviceNames device_names; |
148 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); | 50 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); |
149 | 51 |
150 StreamDeviceInfoArray devices; | 52 StreamDeviceInfoArray devices; |
151 for (media::AudioDeviceNames::iterator it = device_names.begin(); | 53 for (media::AudioDeviceNames::iterator it = device_names.begin(); |
152 it != device_names.end(); | 54 it != device_names.end(); |
153 ++it) { | 55 ++it) { |
154 devices.push_back(StreamDeviceInfo(kAudioCapture, it->device_name, | 56 devices.push_back(StreamDeviceInfo(kAudioCapture, it->device_name, |
155 it->unique_id, false)); | 57 it->unique_id, false)); |
156 } | 58 } |
157 | 59 |
60 // Returns the device list through the listener by posting a task on | |
61 // IO thread since MediaStreamManager handles the callback asynchronously. | |
158 BrowserThread::PostTask( | 62 BrowserThread::PostTask( |
159 BrowserThread::IO, | 63 BrowserThread::IO, |
160 FROM_HERE, | 64 FROM_HERE, |
161 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread, | 65 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread, |
162 base::Unretained(this), devices)); | 66 base::Unretained(this), |
67 devices)); | |
tommi (sloooow) - chröme
2011/11/23 20:16:31
won't |devices| go out of scope and thus be garbag
no longer working on chromium
2011/11/24 14:47:34
I did not dig into the details on how the bind wor
henrika (OOO until Aug 14)
2011/11/24 15:22:26
Can probably be done without a copy.
no longer working on chromium
2011/11/24 16:00:42
Use a pointer as Tommi suggests.
| |
163 } | 68 } |
164 | 69 |
165 void AudioInputDeviceManager::OpenOnDeviceThread( | 70 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { |
166 int session_id, const StreamDeviceInfo& device) { | 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
167 DCHECK(IsOnCaptureDeviceThread()); | 72 |
73 // Generate a new id for this device. | |
74 int session_id = next_capture_session_id_++; | |
168 DCHECK(devices_.find(session_id) == devices_.end()); | 75 DCHECK(devices_.find(session_id) == devices_.end()); |
169 | 76 |
170 media::AudioDeviceName audio_input_device_name; | 77 media::AudioDeviceName audio_input_device_name; |
171 audio_input_device_name.device_name = device.name; | 78 audio_input_device_name.device_name = device.name; |
172 audio_input_device_name.unique_id = device.device_id; | 79 audio_input_device_name.unique_id = device.device_id; |
173 | 80 |
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. | 81 // Add the session_id and device to the list. |
181 devices_[session_id] = audio_input_device_name; | 82 devices_[session_id] = audio_input_device_name; |
83 | |
84 // Returns the |session_id| through the listener by posting a task on | |
85 // IO thread since MediaStreamManager handles the callback asynchronously. | |
182 BrowserThread::PostTask(BrowserThread::IO, | 86 BrowserThread::PostTask(BrowserThread::IO, |
183 FROM_HERE, | 87 FROM_HERE, |
184 base::Bind( | 88 base::Bind( |
185 &AudioInputDeviceManager::OpenedOnIOThread, | 89 &AudioInputDeviceManager::OpenedOnIOThread, |
henrika (OOO until Aug 14)
2011/11/24 15:22:26
Odd indentation.
no longer working on chromium
2011/11/24 16:00:42
Done.
| |
186 base::Unretained(this), | 90 base::Unretained(this), |
187 session_id)); | 91 session_id)); |
92 | |
93 return session_id; | |
188 } | 94 } |
189 | 95 |
190 void AudioInputDeviceManager::CloseOnDeviceThread(int session_id) { | 96 void AudioInputDeviceManager::Close(int session_id) { |
191 DCHECK(IsOnCaptureDeviceThread()); | 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
98 DCHECK(listener_); | |
192 DCHECK(devices_.find(session_id) != devices_.end()); | 99 DCHECK(devices_.find(session_id) != devices_.end()); |
193 | 100 |
194 devices_.erase(session_id); | 101 devices_.erase(session_id); |
102 | |
103 // Checks if the device has been stopped, if not, sends stop signal. | |
104 EventHandlerMap::iterator it = event_handlers_.find(session_id); | |
105 if (it != event_handlers_.end()) { | |
106 it->second->OnDeviceStopped(session_id); | |
107 event_handlers_.erase(session_id); | |
108 } | |
109 | |
110 // Posts a callback through the listener on IO thread since | |
111 // MediaStreamManager handles the callback asynchronously. | |
195 BrowserThread::PostTask(BrowserThread::IO, | 112 BrowserThread::PostTask(BrowserThread::IO, |
196 FROM_HERE, | 113 FROM_HERE, |
197 base::Bind( | 114 base::Bind( |
198 &AudioInputDeviceManager::ClosedOnIOThread, | 115 &AudioInputDeviceManager::ClosedOnIOThread, |
henrika (OOO until Aug 14)
2011/11/24 15:22:26
Fix indentation.
no longer working on chromium
2011/11/24 16:00:42
Done.
| |
199 base::Unretained(this), | 116 base::Unretained(this), |
200 session_id)); | 117 session_id)); |
201 } | 118 } |
202 | 119 |
203 void AudioInputDeviceManager::StartOnDeviceThread(const int session_id) { | 120 void AudioInputDeviceManager::Start( |
204 DCHECK(IsOnCaptureDeviceThread()); | 121 int session_id, AudioInputDeviceManagerEventHandler* event_handler) { |
tommi (sloooow) - chröme
2011/11/23 20:16:31
move int session_id to the previous line
no longer working on chromium
2011/11/24 14:47:34
"AudioInputDeviceManagerEventHandler* event_handle
| |
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
123 DCHECK(event_handler); | |
205 | 124 |
206 // Get the up-to-date device enumeration list from the OS and find out | 125 // Solution for not using MediaStreamManager. This is needed when Start() is |
207 // the unique id of the device. | 126 // called without using Open(), we post default device for test purpose. |
208 std::string device_id = kInvalidDeviceId; | 127 // And we do not store the info for the kFakeOpenSessionId but return |
209 AudioInputDeviceMap::const_iterator it = devices_.find(session_id); | 128 // the callback immediately. |
210 if (it != devices_.end()) { | 129 if (session_id == kFakeOpenSessionId) { |
211 media::AudioDeviceNames device_names; | 130 event_handler->OnDeviceStarted(session_id, |
212 AudioManager::GetAudioManager()->GetAudioInputDeviceNames(&device_names); | 131 AudioManagerBase::kDefaultDeviceId); |
213 if (!device_names.empty()) { | 132 return; |
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 } | 133 } |
227 | 134 |
228 // Posts the index to AudioInputRenderHost through the event handler. | 135 // Checks if the device has been opened or not. |
229 BrowserThread::PostTask(BrowserThread::IO, | 136 std::string device_id = (devices_.find(session_id) == devices_.end()) ? |
230 FROM_HERE, | 137 kInvalidDeviceId : devices_[session_id].unique_id; |
231 base::Bind( | 138 |
232 &AudioInputDeviceManager::StartedOnIOThread, | 139 // Adds the event handler to the session if the session has not been started, |
233 base::Unretained(this), | 140 // otherwise post a |kInvalidDeviceId| to indicate that Start() fails. |
234 session_id, | 141 if (event_handlers_.find(session_id) == event_handlers_.end()) |
235 device_id)); | 142 event_handlers_.insert(std::make_pair(session_id, event_handler)); |
143 else | |
144 device_id = kInvalidDeviceId; | |
145 | |
146 // Post a callback through the AudioInputRendererHost to notify the renderer | |
147 // device has been started. | |
148 event_handler->OnDeviceStarted(session_id, device_id); | |
236 } | 149 } |
237 | 150 |
238 void AudioInputDeviceManager::StopOnDeviceThread(int session_id) { | 151 void AudioInputDeviceManager::Stop(int session_id) { |
239 DCHECK(IsOnCaptureDeviceThread()); | 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
240 BrowserThread::PostTask(BrowserThread::IO, | 153 |
241 FROM_HERE, | 154 // Erase the event handler referenced by the session_id. |
242 base::Bind( | 155 event_handlers_.erase(session_id); |
243 &AudioInputDeviceManager::StoppedOnIOThread, | |
244 base::Unretained(this), | |
245 session_id)); | |
246 } | 156 } |
247 | 157 |
248 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( | 158 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( |
249 const StreamDeviceInfoArray& devices) { | 159 const StreamDeviceInfoArray& devices) { |
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
251 if (listener_) | 161 if (listener_) |
252 listener_->DevicesEnumerated(kAudioCapture, devices); | 162 listener_->DevicesEnumerated(kAudioCapture, devices); |
253 } | 163 } |
254 | 164 |
255 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) { | 165 void AudioInputDeviceManager::OpenedOnIOThread(int session_id) { |
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
257 if (listener_) | 167 if (listener_) |
258 listener_->Opened(kAudioCapture, session_id); | 168 listener_->Opened(kAudioCapture, session_id); |
259 } | 169 } |
260 | 170 |
261 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { | 171 void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { |
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 172 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_) | 173 if (listener_) |
277 listener_->Error(kAudioCapture, session_id, error); | 174 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 } | 175 } |
327 | 176 |
328 } // namespace media_stream | 177 } // namespace media_stream |
OLD | NEW |