Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: content/browser/media_stream/video_capture_manager.cc

Issue 6946001: VideoCaptureManager opens/closes, starts/stops and enumerates video capture devices. VideoCapture... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: VideoCaptureManager.cc error check changes Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/media_stream/video_capture_manager.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "content/browser/browser_thread.h"
9 #include "media/video/capture/fake_video_capture_device.h"
10 #include "media/video/capture/video_capture_device.h"
11
12 namespace media_stream {
13
14 // Starting id for the first capture session
15 enum { kFirstSessionId = 2};
16
17 static ::base::LazyInstance<VideoCaptureManager> g_video_capture_manager(
18 base::LINKER_INITIALIZED);
19
20 bool VideoCaptureManager::use_fake_device_ = false;
John Knottenbelt 2011/05/11 11:36:35 Question: Can you make use_fake_device_ non-static
mflodman1 2011/05/15 20:24:00 Done.
21
22 VideoCaptureManager* VideoCaptureManager::Get() {
23 return g_video_capture_manager.Pointer();
24 }
25
26 void VideoCaptureManager::CreateTestManager() {
John Knottenbelt 2011/05/11 11:36:35 Suggestion: Remove this method and make UseFakeDev
mflodman1 2011/05/15 20:24:00 Done.
27 VideoCaptureManager* vcm = g_video_capture_manager.Pointer();
28 vcm->UseFakeDevice();
29 }
30
31 VideoCaptureManager::VideoCaptureManager()
32 : vc_device_thread_("VideoCaptureManagerThread"),
33 listener_(NULL),
34 new_capture_session_id_(kFirstSessionId),
35 devices_() {
36 vc_device_thread_.Start();
37 }
38
39 VideoCaptureManager::~VideoCaptureManager() {
40 vc_device_thread_.Stop();
41 devices_.clear();
John Knottenbelt 2011/05/11 11:36:35 devices_ will be cleared by virtue of its destruct
mflodman1 2011/05/15 20:24:00 Done.
42 }
43
44 bool VideoCaptureManager::Register(MediaStreamType service_type,
45 MediaStreamProviderListener* listener) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
47 if (service_type != kVideoCapture) {
John Knottenbelt 2011/05/11 11:36:35 Nit (here, and elsewhere): Single line body should
mflodman1 2011/05/15 20:24:00 Earlier code review (for VideoCaptureDeviceLinux)
48 // Not a valid service type
49 return false;
50 }
51 if (listener_) {
John Knottenbelt 2011/05/11 11:36:35 Question (here, and elsewhere): Is it a logic erro
mflodman1 2011/05/15 20:24:00 Done.
52 // Already registered, unregister first.
53 return false;
54 }
55 listener_ = listener;
56 return true;
57 }
58
59 void VideoCaptureManager::Unregister(MediaStreamType service_type,
60 MediaStreamProviderListener* listener) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
62 if (service_type != kVideoCapture) {
63 return;
64 }
65 listener_ = NULL;
66 return;
John Knottenbelt 2011/05/11 11:36:35 Nit (here and elsewhere): Unnecessary final return
mflodman1 2011/05/15 20:24:00 Done.
67 }
68
69 void VideoCaptureManager::EnumerateDevices(MediaStreamType service_type) {
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71 if (listener_ == NULL) {
72 return;
73 }
74 if (service_type != kVideoCapture) {
75 PostOnError(-1, kInvalidMediaStreamType);
John Knottenbelt 2011/05/11 11:36:35 Suggestion: Introduce a constant, e.g. kInvalidMed
mflodman1 2011/05/15 20:24:00 servive_type removed, but invalid id added as retu
76 return;
77 }
78
79 vc_device_thread_.message_loop()->PostTask(
80 FROM_HERE,
81 NewRunnableMethod(this,
82 &VideoCaptureManager::OnEnumerateDevices));
83 return;
84 }
85
86 MediaCaptureSessionId VideoCaptureManager::Open(
87 MediaStreamType service_type, const MediaCaptureDeviceInfo& device) {
88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
89 if (listener_ == NULL) {
90 return -1;
91 }
92 if (service_type != kVideoCapture) {
93 PostOnError(-1, kInvalidMediaStreamType);
94 return -1;
95 }
96
97 // Generate a new id for this device
98 MediaCaptureSessionId video_capture_session_id = new_capture_session_id_++;
99
100 vc_device_thread_.message_loop()->PostTask(
101 FROM_HERE,
102 NewRunnableMethod(this,
103 &VideoCaptureManager::OnOpen,
104 video_capture_session_id,
105 device));
106
107 return video_capture_session_id;
108 }
109
110 void VideoCaptureManager::Close(MediaStreamType service_type,
111 MediaCaptureSessionId capture_session_id) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
113 if (listener_ == NULL) {
114 return;
115 }
116 if (service_type != kVideoCapture) {
117 PostOnError(-1, kInvalidMediaStreamType);
118 return;
119 }
120
121 vc_device_thread_.message_loop()->PostTask(
122 FROM_HERE,
123 NewRunnableMethod(this,
124 &VideoCaptureManager::OnClose,
125 capture_session_id));
126 return;
127 }
128
129 void VideoCaptureManager::Start(
130 const media::VideoCaptureParams& capture_params,
131 media::VideoCaptureDevice::EventHandler* video_capture_receiver) {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
133
134 vc_device_thread_.message_loop()->PostTask(
135 FROM_HERE,
136 NewRunnableMethod(this,
137 &VideoCaptureManager::OnStart,
138 capture_params,
139 video_capture_receiver));
140 }
141
142 void VideoCaptureManager::Stop(
143 const media::VideoCaptureSessionId capture_session_id, Task* stopped_task) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
145
146 vc_device_thread_.message_loop()->PostTask(
147 FROM_HERE,
148 NewRunnableMethod(this,
149 &VideoCaptureManager::OnStop,
150 capture_session_id,
151 stopped_task));
152 }
153
154 void VideoCaptureManager::OnEnumerateDevices() {
155 DCHECK(IsOnCaptureDeviceThread());
156
157 scoped_ptr<media::VideoCaptureDevice::Names> device_names(
158 new media::VideoCaptureDevice::Names());
159 GetAvailableDevices(device_names.get());
160
161 MediaCaptureDevices devices;
162 for (media::VideoCaptureDevice::Names::iterator it =
163 device_names.get()->begin(); it != device_names.get()->end(); ++it) {
164 bool opened = DeviceOpened(*it);
165 devices.push_back(MediaCaptureDeviceInfo(kVideoCapture, it->device_name,
166 it->unique_id, opened));
167 }
168
169 // Let the listener know the result
170 PostOnDevicesEnumerated(devices);
171
172 // Clean-up
173 devices.clear();
174 device_names.get()->clear();
175
176 return;
177 }
178
179 void VideoCaptureManager::OnOpen(MediaCaptureSessionId capture_session_id,
180 const MediaCaptureDeviceInfo device) {
181 DCHECK(IsOnCaptureDeviceThread());
182 if (devices_.find(capture_session_id) != devices_.end()) {
John Knottenbelt 2011/05/11 11:36:35 Question: Is it appropriate to add more DCHECKs in
mflodman1 2011/05/15 20:24:00 Yes, changed.
183 // id already exists!
184 PostOnError(capture_session_id, kInvalidSession);
185 return;
186 }
187
188 // Check if another session has already opened this device, only one user per
189 // device is supported.
190 if (DeviceOpened(device) == true) {
John Knottenbelt 2011/05/11 11:36:35 Nit: Remove == true
mflodman1 2011/05/15 20:24:00 Done.
191 PostOnError(capture_session_id, kDeviceAlreadyInUse);
192 return;
193 }
194
195 // Open the device
196 media::VideoCaptureDevice::Name vc_device_name;
197 vc_device_name.device_name = device.name;
198 vc_device_name.unique_id = device.device_id;
199
200 media::VideoCaptureDevice* video_capture_device = NULL;
201 if (!use_fake_device_) {
202 video_capture_device = media::VideoCaptureDevice::Create(vc_device_name);
203 } else {
204 video_capture_device =
205 media::FakeVideoCaptureDevice::Create(vc_device_name);
206 }
207 if (video_capture_device == NULL) {
208 PostOnError(capture_session_id, kDeviceNotAvailable);
209 return;
210 }
211
212 devices_[capture_session_id] = video_capture_device;
213 PostOnOpened(capture_session_id);
214 return;
215 }
216
217 void VideoCaptureManager::OnClose(
218 MediaCaptureSessionId capture_session_id) {
219 DCHECK(IsOnCaptureDeviceThread());
220
221 VideoCaptureDevices::iterator it = devices_.find(capture_session_id);
222 if (it != devices_.end()) {
223 // Deallocate (if not done already) and delete the device
224 media::VideoCaptureDevice* video_capture_device = it->second;
225 video_capture_device->DeAllocate();
226 delete video_capture_device;
227 devices_.erase(it);
228 }
229
230 PostOnClosed(capture_session_id);
231 return;
232 }
233
234 void VideoCaptureManager::OnStart(
235 const media::VideoCaptureParams capture_params,
236 media::VideoCaptureDevice::EventHandler* video_capture_receiver) {
237 DCHECK(IsOnCaptureDeviceThread());
238
239 // Solution for not using MediaStreamManager
240 // This session id won't be returned by Open()
241 if (capture_params.session_id == kStartOpenSessionId) {
John Knottenbelt 2011/05/11 11:36:35 Question: This seems like a convenience feature. I
mflodman1 2011/05/15 20:24:00 It is used to be able to open capture devices in C
242 // Start() is called without using Open(), we need to open a device
243 scoped_ptr<media::VideoCaptureDevice::Names> device_names(
244 new media::VideoCaptureDevice::Names());
245 GetAvailableDevices(device_names.get());
246
247 MediaCaptureDeviceInfo device(kVideoCapture,
248 device_names.get()->front().device_name,
249 device_names.get()->front().unique_id, false);
250
251 // Call OnOpen to open using the first device in the list
252 OnOpen(capture_params.session_id, device);
253 }
254
255 VideoCaptureDevices::iterator it = devices_.find(capture_params.session_id);
256 if (it == devices_.end()) {
257 // Invalid session id
258 video_capture_receiver->OnError();
259 return;
260 }
261 media::VideoCaptureDevice* video_capture_device = it->second;
262
263 // Possible errors are signaled to video_capture_receiver by
264 // video_capture_device. video_capture_receiver to perform actions.
265 video_capture_device->Allocate(capture_params.width, capture_params.height,
266 capture_params.frame_per_second,
267 video_capture_receiver);
268 video_capture_device->Start();
269 return;
270 }
271
272 void VideoCaptureManager::OnStop(
273 const media::VideoCaptureSessionId capture_session_id,
274 Task* stopped_task) {
275 DCHECK(IsOnCaptureDeviceThread());
276
277 VideoCaptureDevices::iterator it = devices_.find(capture_session_id);
278 if (it != devices_.end()) {
279 media::VideoCaptureDevice* video_capture_device = it->second;
280 // Possible errors are signaled to video_capture_receiver by
281 // video_capture_device. video_capture_receiver to perform actions.
282 video_capture_device->Stop();
283 video_capture_device->DeAllocate();
284 }
285
286 if (stopped_task) {
287 stopped_task->Run();
288 delete stopped_task;
289 }
290
291 if (capture_session_id == kStartOpenSessionId) {
292 // This device was opened from Start(), not Open(). Close it!
293 OnClose(capture_session_id);
294 }
295 return;
296 }
297
298 void VideoCaptureManager::OnOpened(
299 MediaCaptureSessionId capture_session_id) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 if (listener_ == NULL) {
302 // Listener has been removed
303 return;
304 }
305 listener_->Opened(kVideoCapture, capture_session_id);
306 return;
307 }
308
309 void VideoCaptureManager::OnClosed(
310 MediaCaptureSessionId capture_session_id) {
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
312 if (listener_ == NULL) {
313 // Listener has been removed
314 return;
315 }
316 listener_->Closed(kVideoCapture, capture_session_id);
317 return;
318 }
319
320 void VideoCaptureManager::OnDevicesEnumerated(
321 const MediaCaptureDevices& devices) {
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
323 if (listener_ == NULL) {
324 // Listener has been removed
325 return;
326 }
327 listener_->DevicesEnumerated(kVideoCapture, devices);
328 return;
329 }
330
331 void VideoCaptureManager::OnError(MediaCaptureSessionId capture_session_id,
332 MediaStreamProviderError error) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
334 if (listener_ == NULL) {
335 // Listener has been removed
336 return;
337 }
338 listener_->Error(kVideoCapture, capture_session_id, error);
339 return;
340 }
341
342 void VideoCaptureManager::PostOnOpened(
343 MediaCaptureSessionId capture_session_id) {
344 DCHECK(IsOnCaptureDeviceThread());
345 BrowserThread::PostTask(BrowserThread::IO,
346 FROM_HERE,
347 NewRunnableMethod(this,
348 &VideoCaptureManager::OnOpened,
349 capture_session_id));
350 return;
351 }
352
353 void VideoCaptureManager::PostOnClosed(
354 MediaCaptureSessionId capture_session_id) {
355 DCHECK(IsOnCaptureDeviceThread());
356 BrowserThread::PostTask(BrowserThread::IO,
357 FROM_HERE,
358 NewRunnableMethod(this,
359 &VideoCaptureManager::OnClosed,
360 capture_session_id));
361 return;
362 }
363
364 void VideoCaptureManager::PostOnDevicesEnumerated(MediaCaptureDevices devices) {
365 DCHECK(IsOnCaptureDeviceThread());
366
367 BrowserThread::PostTask(BrowserThread::IO,
368 FROM_HERE,
369 NewRunnableMethod(
370 this,
371 &VideoCaptureManager::OnDevicesEnumerated,
372 devices));
373 return;
374 }
375
376 void VideoCaptureManager::PostOnError(MediaCaptureSessionId capture_session_id,
377 MediaStreamProviderError error) {
378 // Don't check thread here, can be called from both IO thread and device
379 // thread.
380 BrowserThread::PostTask(BrowserThread::IO,
381 FROM_HERE,
382 NewRunnableMethod(this,
383 &VideoCaptureManager::OnError,
384 capture_session_id,
385 error));
John Knottenbelt 2011/05/11 11:36:35 Nit: indentation
mflodman1 2011/05/15 20:24:00 Done.
386 return;
387 }
388
389 bool VideoCaptureManager::IsOnCaptureDeviceThread() const {
390 return MessageLoop::current() == vc_device_thread_.message_loop();
391 }
392
393 void VideoCaptureManager::GetAvailableDevices(
394 media::VideoCaptureDevice::Names* device_names) {
395 DCHECK(IsOnCaptureDeviceThread());
396
397 if (!use_fake_device_) {
398 media::VideoCaptureDevice::GetDeviceNames(device_names);
399 } else {
400 media::FakeVideoCaptureDevice::GetDeviceNames(device_names);
401 }
402 return;
403 }
404
405 bool VideoCaptureManager::DeviceOpened(
406 const media::VideoCaptureDevice::Name& device_name) {
407 DCHECK(IsOnCaptureDeviceThread());
408
409 for (VideoCaptureDevices::iterator it = devices_.begin();
410 it != devices_.end();
411 ++it) {
412 if (device_name.unique_id.compare(it->second->device_name().unique_id) ==
John Knottenbelt 2011/05/11 11:36:35 I think we can use a directy comparison (==) inste
mflodman1 2011/05/15 20:24:00 Done.
413 0) {
414 // We've found the device!
415 return true;
416 }
417 }
418 return false;
419 }
420
421 bool VideoCaptureManager::DeviceOpened(
John Knottenbelt 2011/05/11 11:36:35 Add DCHECK to ensure/document what thread this met
mflodman1 2011/05/15 20:24:00 Done.
422 const MediaCaptureDeviceInfo& device_info) {
423 for (VideoCaptureDevices::iterator it = devices_.begin();
424 it != devices_.end();
425 it++) {
426 if (device_info.device_id.compare(it->second->device_name().unique_id) ==
427 0) {
428 return true;
429 }
430 }
431 return false;
432 }
433
434 void VideoCaptureManager::UseFakeDevice() {
435 use_fake_device_ = true;
436 }
437
438 MessageLoop* VideoCaptureManager::GetMessageLoop() {
439 return vc_device_thread_.message_loop();
440 }
441
442 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698