• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/renderer_host/media/video_capture_manager.h"
6 
7 #include <set>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/task_runner_util.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "content/browser/media/capture/web_contents_video_capture_device.h"
17 #include "content/browser/renderer_host/media/video_capture_controller.h"
18 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/desktop_media_id.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/media_stream_request.h"
23 #include "media/base/bind_to_current_loop.h"
24 #include "media/base/scoped_histogram_timer.h"
25 #include "media/video/capture/video_capture_device.h"
26 #include "media/video/capture/video_capture_device_factory.h"
27 
28 #if defined(ENABLE_SCREEN_CAPTURE)
29 #include "content/browser/media/capture/desktop_capture_device.h"
30 #if defined(USE_AURA)
31 #include "content/browser/media/capture/desktop_capture_device_aura.h"
32 #endif
33 #endif
34 
35 namespace {
36 
37 // Compares two VideoCaptureFormat by checking smallest frame_size area, then
38 // by _largest_ frame_rate. Used to order a VideoCaptureFormats vector so that
39 // the first entry for a given resolution has the largest frame rate, as needed
40 // by the ConsolidateCaptureFormats() method.
IsCaptureFormatSmaller(const media::VideoCaptureFormat & format1,const media::VideoCaptureFormat & format2)41 bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1,
42                             const media::VideoCaptureFormat& format2) {
43   if (format1.frame_size.GetArea() == format2.frame_size.GetArea())
44     return format1.frame_rate > format2.frame_rate;
45   return format1.frame_size.GetArea() < format2.frame_size.GetArea();
46 }
47 
IsCaptureFormatSizeEqual(const media::VideoCaptureFormat & format1,const media::VideoCaptureFormat & format2)48 bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1,
49                               const media::VideoCaptureFormat& format2) {
50   return format1.frame_size.GetArea() == format2.frame_size.GetArea();
51 }
52 
53 // This function receives a list of capture formats, removes duplicated
54 // resolutions while keeping the highest frame rate for each, and forcing I420
55 // pixel format.
ConsolidateCaptureFormats(media::VideoCaptureFormats * formats)56 void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) {
57   if (formats->empty())
58     return;
59   std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller);
60   // Due to the ordering imposed, the largest frame_rate is kept while removing
61   // duplicated resolutions.
62   media::VideoCaptureFormats::iterator last =
63       std::unique(formats->begin(), formats->end(), IsCaptureFormatSizeEqual);
64   formats->erase(last, formats->end());
65   // Mark all formats as I420, since this is what the renderer side will get
66   // anyhow: the actual pixel format is decided at the device level.
67   for (media::VideoCaptureFormats::iterator it = formats->begin();
68        it != formats->end(); ++it) {
69     it->pixel_format = media::PIXEL_FORMAT_I420;
70   }
71 }
72 
73 }  // namespace
74 
75 namespace content {
76 
DeviceEntry(MediaStreamType stream_type,const std::string & id,scoped_ptr<VideoCaptureController> controller)77 VideoCaptureManager::DeviceEntry::DeviceEntry(
78     MediaStreamType stream_type,
79     const std::string& id,
80     scoped_ptr<VideoCaptureController> controller)
81     : stream_type(stream_type),
82       id(id),
83       video_capture_controller(controller.Pass()) {}
84 
~DeviceEntry()85 VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
86 
DeviceInfo()87 VideoCaptureManager::DeviceInfo::DeviceInfo() {}
88 
DeviceInfo(const media::VideoCaptureDevice::Name & name,const media::VideoCaptureFormats & supported_formats)89 VideoCaptureManager::DeviceInfo::DeviceInfo(
90     const media::VideoCaptureDevice::Name& name,
91     const media::VideoCaptureFormats& supported_formats)
92     : name(name),
93       supported_formats(supported_formats) {}
94 
~DeviceInfo()95 VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
96 
VideoCaptureManager(scoped_ptr<media::VideoCaptureDeviceFactory> factory)97 VideoCaptureManager::VideoCaptureManager(
98     scoped_ptr<media::VideoCaptureDeviceFactory> factory)
99     : listener_(NULL),
100       new_capture_session_id_(1),
101       video_capture_device_factory_(factory.Pass()) {
102 }
103 
~VideoCaptureManager()104 VideoCaptureManager::~VideoCaptureManager() {
105   DCHECK(devices_.empty());
106 }
107 
Register(MediaStreamProviderListener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & device_task_runner)108 void VideoCaptureManager::Register(
109     MediaStreamProviderListener* listener,
110     const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
111   DCHECK_CURRENTLY_ON(BrowserThread::IO);
112   DCHECK(!listener_);
113   DCHECK(!device_task_runner_.get());
114   listener_ = listener;
115   device_task_runner_ = device_task_runner;
116 }
117 
Unregister()118 void VideoCaptureManager::Unregister() {
119   DCHECK(listener_);
120   listener_ = NULL;
121 }
122 
EnumerateDevices(MediaStreamType stream_type)123 void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
124   DCHECK_CURRENTLY_ON(BrowserThread::IO);
125   DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type;
126   DCHECK(listener_);
127   DCHECK_EQ(stream_type, MEDIA_DEVICE_VIDEO_CAPTURE);
128 
129   // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument
130   // for another callback to OnDevicesInfoEnumerated() to be run in the current
131   // loop, i.e. IO loop. Pass a timer for UMA histogram collection.
132   base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>
133       devices_enumerated_callback =
134           base::Bind(&VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread,
135                      this,
136                      media::BindToCurrentLoop(base::Bind(
137                          &VideoCaptureManager::OnDevicesInfoEnumerated,
138                          this,
139                          stream_type,
140                          base::Owned(new base::ElapsedTimer()))),
141                      stream_type,
142                      devices_info_cache_);
143   // OK to use base::Unretained() since we own the VCDFactory and |this| is
144   // bound in |devices_enumerated_callback|.
145   device_task_runner_->PostTask(FROM_HERE,
146       base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceNames,
147                  base::Unretained(video_capture_device_factory_.get()),
148                  devices_enumerated_callback));
149 }
150 
Open(const StreamDeviceInfo & device_info)151 int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
152   DCHECK_CURRENTLY_ON(BrowserThread::IO);
153   DCHECK(listener_);
154 
155   // Generate a new id for the session being opened.
156   const media::VideoCaptureSessionId capture_session_id =
157       new_capture_session_id_++;
158 
159   DCHECK(sessions_.find(capture_session_id) == sessions_.end());
160   DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id;
161 
162   // We just save the stream info for processing later.
163   sessions_[capture_session_id] = device_info.device;
164 
165   // Notify our listener asynchronously; this ensures that we return
166   // |capture_session_id| to the caller of this function before using that same
167   // id in a listener event.
168   base::MessageLoop::current()->PostTask(FROM_HERE,
169       base::Bind(&VideoCaptureManager::OnOpened, this,
170                  device_info.device.type, capture_session_id));
171   return capture_session_id;
172 }
173 
Close(int capture_session_id)174 void VideoCaptureManager::Close(int capture_session_id) {
175   DCHECK_CURRENTLY_ON(BrowserThread::IO);
176   DCHECK(listener_);
177   DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
178 
179   SessionMap::iterator session_it = sessions_.find(capture_session_id);
180   if (session_it == sessions_.end()) {
181     NOTREACHED();
182     return;
183   }
184 
185   DeviceEntry* const existing_device = GetDeviceEntryForMediaStreamDevice(
186       session_it->second);
187   if (existing_device) {
188     // Remove any client that is still using the session. This is safe to call
189     // even if there are no clients using the session.
190     existing_device->video_capture_controller->StopSession(capture_session_id);
191 
192     // StopSession() may have removed the last client, so we might need to
193     // close the device.
194     DestroyDeviceEntryIfNoClients(existing_device);
195   }
196 
197   // Notify listeners asynchronously, and forget the session.
198   base::MessageLoop::current()->PostTask(FROM_HERE,
199       base::Bind(&VideoCaptureManager::OnClosed, this, session_it->second.type,
200                  capture_session_id));
201   sessions_.erase(session_it);
202 }
203 
DoStartDeviceOnDeviceThread(media::VideoCaptureSessionId session_id,DeviceEntry * entry,const media::VideoCaptureParams & params,scoped_ptr<media::VideoCaptureDevice::Client> device_client)204 void VideoCaptureManager::DoStartDeviceOnDeviceThread(
205     media::VideoCaptureSessionId session_id,
206     DeviceEntry* entry,
207     const media::VideoCaptureParams& params,
208     scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
209   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
210   DCHECK(IsOnDeviceThread());
211 
212   scoped_ptr<media::VideoCaptureDevice> video_capture_device;
213   switch (entry->stream_type) {
214     case MEDIA_DEVICE_VIDEO_CAPTURE: {
215       // We look up the device id from the renderer in our local enumeration
216       // since the renderer does not have all the information that might be
217       // held in the browser-side VideoCaptureDevice::Name structure.
218       DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_);
219       if (found) {
220         video_capture_device =
221             video_capture_device_factory_->Create(found->name);
222       }
223       break;
224     }
225     case MEDIA_TAB_VIDEO_CAPTURE: {
226       video_capture_device.reset(
227           WebContentsVideoCaptureDevice::Create(entry->id));
228       break;
229     }
230     case MEDIA_DESKTOP_VIDEO_CAPTURE: {
231 #if defined(ENABLE_SCREEN_CAPTURE)
232       DesktopMediaID id = DesktopMediaID::Parse(entry->id);
233 #if defined(USE_AURA)
234       if (id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
235         video_capture_device.reset(DesktopCaptureDeviceAura::Create(id));
236       } else
237 #endif
238       if (id.type != DesktopMediaID::TYPE_NONE &&
239           id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
240         video_capture_device = DesktopCaptureDevice::Create(id);
241         if (notification_window_ids_.find(session_id) !=
242             notification_window_ids_.end()) {
243           static_cast<DesktopCaptureDevice*>(video_capture_device.get())
244               ->SetNotificationWindowId(notification_window_ids_[session_id]);
245         }
246       }
247 #endif  // defined(ENABLE_SCREEN_CAPTURE)
248       break;
249     }
250     default: {
251       NOTIMPLEMENTED();
252       break;
253     }
254   }
255 
256   if (!video_capture_device) {
257     device_client->OnError("Could not create capture device");
258     return;
259   }
260 
261   video_capture_device->AllocateAndStart(params, device_client.Pass());
262   entry->video_capture_device = video_capture_device.Pass();
263 }
264 
StartCaptureForClient(media::VideoCaptureSessionId session_id,const media::VideoCaptureParams & params,base::ProcessHandle client_render_process,VideoCaptureControllerID client_id,VideoCaptureControllerEventHandler * client_handler,const DoneCB & done_cb)265 void VideoCaptureManager::StartCaptureForClient(
266     media::VideoCaptureSessionId session_id,
267     const media::VideoCaptureParams& params,
268     base::ProcessHandle client_render_process,
269     VideoCaptureControllerID client_id,
270     VideoCaptureControllerEventHandler* client_handler,
271     const DoneCB& done_cb) {
272   DCHECK_CURRENTLY_ON(BrowserThread::IO);
273   DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, "
274            << params.requested_format.frame_size.ToString() << ", "
275            << params.requested_format.frame_rate << ", #" << session_id << ")";
276 
277   DeviceEntry* entry = GetOrCreateDeviceEntry(session_id);
278   if (!entry) {
279     done_cb.Run(base::WeakPtr<VideoCaptureController>());
280     return;
281   }
282 
283   DCHECK(entry->video_capture_controller);
284 
285   // First client starts the device.
286   if (entry->video_capture_controller->GetClientCount() == 0) {
287     DVLOG(1) << "VideoCaptureManager starting device (type = "
288              << entry->stream_type << ", id = " << entry->id << ")";
289 
290     device_task_runner_->PostTask(
291         FROM_HERE,
292         base::Bind(
293             &VideoCaptureManager::DoStartDeviceOnDeviceThread,
294             this,
295             session_id,
296             entry,
297             params,
298             base::Passed(entry->video_capture_controller->NewDeviceClient())));
299   }
300   // Run the callback first, as AddClient() may trigger OnFrameInfo().
301   done_cb.Run(entry->video_capture_controller->GetWeakPtr());
302   entry->video_capture_controller->AddClient(
303       client_id, client_handler, client_render_process, session_id, params);
304 }
305 
StopCaptureForClient(VideoCaptureController * controller,VideoCaptureControllerID client_id,VideoCaptureControllerEventHandler * client_handler,bool aborted_due_to_error)306 void VideoCaptureManager::StopCaptureForClient(
307     VideoCaptureController* controller,
308     VideoCaptureControllerID client_id,
309     VideoCaptureControllerEventHandler* client_handler,
310     bool aborted_due_to_error) {
311   DCHECK_CURRENTLY_ON(BrowserThread::IO);
312   DCHECK(controller);
313   DCHECK(client_handler);
314 
315   DeviceEntry* entry = GetDeviceEntryForController(controller);
316   if (!entry) {
317     NOTREACHED();
318     return;
319   }
320   if (aborted_due_to_error) {
321     SessionMap::iterator it;
322     for (it = sessions_.begin(); it != sessions_.end(); ++it) {
323       if (it->second.type == entry->stream_type &&
324           it->second.id == entry->id) {
325         listener_->Aborted(it->second.type, it->first);
326         break;
327       }
328     }
329   }
330 
331   // Detach client from controller.
332   media::VideoCaptureSessionId session_id =
333       controller->RemoveClient(client_id, client_handler);
334   DVLOG(1) << "VideoCaptureManager::StopCaptureForClient, session_id = "
335            << session_id;
336 
337   // If controller has no more clients, delete controller and device.
338   DestroyDeviceEntryIfNoClients(entry);
339 }
340 
GetDeviceSupportedFormats(media::VideoCaptureSessionId capture_session_id,media::VideoCaptureFormats * supported_formats)341 bool VideoCaptureManager::GetDeviceSupportedFormats(
342     media::VideoCaptureSessionId capture_session_id,
343     media::VideoCaptureFormats* supported_formats) {
344   DCHECK_CURRENTLY_ON(BrowserThread::IO);
345   DCHECK(supported_formats->empty());
346 
347   SessionMap::iterator it = sessions_.find(capture_session_id);
348   if (it == sessions_.end())
349     return false;
350   DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
351 
352   // Return all available formats of the device, regardless its started state.
353   DeviceInfo* existing_device =
354       FindDeviceInfoById(it->second.id, devices_info_cache_);
355   if (existing_device)
356     *supported_formats = existing_device->supported_formats;
357   return true;
358 }
359 
GetDeviceFormatsInUse(media::VideoCaptureSessionId capture_session_id,media::VideoCaptureFormats * formats_in_use)360 bool VideoCaptureManager::GetDeviceFormatsInUse(
361     media::VideoCaptureSessionId capture_session_id,
362     media::VideoCaptureFormats* formats_in_use) {
363   DCHECK_CURRENTLY_ON(BrowserThread::IO);
364   DCHECK(formats_in_use->empty());
365 
366   SessionMap::iterator it = sessions_.find(capture_session_id);
367   if (it == sessions_.end())
368     return false;
369   DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name;
370 
371   // Return the currently in-use format(s) of the device, if it's started.
372   DeviceEntry* device_in_use =
373       GetDeviceEntryForMediaStreamDevice(it->second);
374   if (device_in_use) {
375     // Currently only one format-in-use is supported at the VCC level.
376     formats_in_use->push_back(
377         device_in_use->video_capture_controller->GetVideoCaptureFormat());
378   }
379   return true;
380 }
381 
SetDesktopCaptureWindowId(media::VideoCaptureSessionId session_id,gfx::NativeViewId window_id)382 void VideoCaptureManager::SetDesktopCaptureWindowId(
383     media::VideoCaptureSessionId session_id,
384     gfx::NativeViewId window_id) {
385   DCHECK_CURRENTLY_ON(BrowserThread::IO);
386   SessionMap::iterator session_it = sessions_.find(session_id);
387   if (session_it == sessions_.end()) {
388     device_task_runner_->PostTask(
389         FROM_HERE,
390         base::Bind(
391             &VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread,
392             this,
393             session_id,
394             window_id));
395     return;
396   }
397 
398   DeviceEntry* const existing_device =
399       GetDeviceEntryForMediaStreamDevice(session_it->second);
400   if (!existing_device)
401     return;
402 
403   DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type);
404   DesktopMediaID id = DesktopMediaID::Parse(existing_device->id);
405   if (id.type == DesktopMediaID::TYPE_NONE ||
406       id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
407     return;
408   }
409 
410   device_task_runner_->PostTask(
411       FROM_HERE,
412       base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread,
413                  this,
414                  existing_device,
415                  window_id));
416 }
417 
DoStopDeviceOnDeviceThread(DeviceEntry * entry)418 void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
419   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
420   DCHECK(IsOnDeviceThread());
421   if (entry->video_capture_device) {
422     entry->video_capture_device->StopAndDeAllocate();
423   }
424   entry->video_capture_device.reset();
425 }
426 
OnOpened(MediaStreamType stream_type,media::VideoCaptureSessionId capture_session_id)427 void VideoCaptureManager::OnOpened(
428     MediaStreamType stream_type,
429     media::VideoCaptureSessionId capture_session_id) {
430   DCHECK_CURRENTLY_ON(BrowserThread::IO);
431   if (!listener_) {
432     // Listener has been removed.
433     return;
434   }
435   listener_->Opened(stream_type, capture_session_id);
436 }
437 
OnClosed(MediaStreamType stream_type,media::VideoCaptureSessionId capture_session_id)438 void VideoCaptureManager::OnClosed(
439     MediaStreamType stream_type,
440     media::VideoCaptureSessionId capture_session_id) {
441   DCHECK_CURRENTLY_ON(BrowserThread::IO);
442   if (!listener_) {
443     // Listener has been removed.
444     return;
445   }
446   listener_->Closed(stream_type, capture_session_id);
447 }
448 
OnDevicesInfoEnumerated(MediaStreamType stream_type,base::ElapsedTimer * timer,const DeviceInfos & new_devices_info_cache)449 void VideoCaptureManager::OnDevicesInfoEnumerated(
450     MediaStreamType stream_type,
451     base::ElapsedTimer* timer,
452     const DeviceInfos& new_devices_info_cache) {
453   DCHECK_CURRENTLY_ON(BrowserThread::IO);
454   UMA_HISTOGRAM_TIMES(
455       "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime",
456       timer->Elapsed());
457   if (!listener_) {
458     // Listener has been removed.
459     return;
460   }
461   devices_info_cache_ = new_devices_info_cache;
462 
463   // Walk the |devices_info_cache_| and transform from VCD::Name to
464   // StreamDeviceInfo for return purposes.
465   StreamDeviceInfoArray devices;
466   for (DeviceInfos::const_iterator it = devices_info_cache_.begin();
467        it != devices_info_cache_.end(); ++it) {
468     devices.push_back(StreamDeviceInfo(
469         stream_type, it->name.GetNameAndModel(), it->name.id()));
470   }
471   listener_->DevicesEnumerated(stream_type, devices);
472 }
473 
IsOnDeviceThread() const474 bool VideoCaptureManager::IsOnDeviceThread() const {
475   return device_task_runner_->BelongsToCurrentThread();
476 }
477 
ConsolidateDevicesInfoOnDeviceThread(base::Callback<void (const DeviceInfos &)> on_devices_enumerated_callback,MediaStreamType stream_type,const DeviceInfos & old_device_info_cache,scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot)478 void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
479     base::Callback<void(const DeviceInfos&)> on_devices_enumerated_callback,
480     MediaStreamType stream_type,
481     const DeviceInfos& old_device_info_cache,
482     scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot) {
483   DCHECK(IsOnDeviceThread());
484   // Construct |new_devices_info_cache| with the cached devices that are still
485   // present in the system, and remove their names from |names_snapshot|, so we
486   // keep there the truly new devices.
487   DeviceInfos new_devices_info_cache;
488   for (DeviceInfos::const_iterator it_device_info =
489            old_device_info_cache.begin();
490        it_device_info != old_device_info_cache.end(); ++it_device_info) {
491      for (media::VideoCaptureDevice::Names::iterator it =
492          names_snapshot->begin();
493           it != names_snapshot->end(); ++it) {
494       if (it_device_info->name.id() == it->id()) {
495         new_devices_info_cache.push_back(*it_device_info);
496         names_snapshot->erase(it);
497         break;
498       }
499     }
500   }
501 
502   // Get the supported capture formats for the new devices in |names_snapshot|.
503   for (media::VideoCaptureDevice::Names::const_iterator it =
504       names_snapshot->begin();
505        it != names_snapshot->end(); ++it) {
506     media::VideoCaptureFormats supported_formats;
507     DeviceInfo device_info(*it, media::VideoCaptureFormats());
508     video_capture_device_factory_->GetDeviceSupportedFormats(
509         *it, &(device_info.supported_formats));
510     ConsolidateCaptureFormats(&device_info.supported_formats);
511     new_devices_info_cache.push_back(device_info);
512   }
513 
514   on_devices_enumerated_callback.Run(new_devices_info_cache);
515 }
516 
517 VideoCaptureManager::DeviceEntry*
GetDeviceEntryForMediaStreamDevice(const MediaStreamDevice & device_info)518 VideoCaptureManager::GetDeviceEntryForMediaStreamDevice(
519     const MediaStreamDevice& device_info) {
520   DCHECK_CURRENTLY_ON(BrowserThread::IO);
521 
522   for (DeviceEntries::iterator it = devices_.begin();
523        it != devices_.end(); ++it) {
524     DeviceEntry* device = *it;
525     if (device_info.type == device->stream_type &&
526         device_info.id == device->id) {
527       return device;
528     }
529   }
530   return NULL;
531 }
532 
533 VideoCaptureManager::DeviceEntry*
GetDeviceEntryForController(const VideoCaptureController * controller) const534 VideoCaptureManager::GetDeviceEntryForController(
535     const VideoCaptureController* controller) const {
536   // Look up |controller| in |devices_|.
537   for (DeviceEntries::const_iterator it = devices_.begin();
538        it != devices_.end(); ++it) {
539     if ((*it)->video_capture_controller.get() == controller) {
540       return *it;
541     }
542   }
543   return NULL;
544 }
545 
DestroyDeviceEntryIfNoClients(DeviceEntry * entry)546 void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
547   DCHECK_CURRENTLY_ON(BrowserThread::IO);
548   // Removal of the last client stops the device.
549   if (entry->video_capture_controller->GetClientCount() == 0) {
550     DVLOG(1) << "VideoCaptureManager stopping device (type = "
551              << entry->stream_type << ", id = " << entry->id << ")";
552 
553     // The DeviceEntry is removed from |devices_| immediately. The controller is
554     // deleted immediately, and the device is freed asynchronously. After this
555     // point, subsequent requests to open this same device ID will create a new
556     // DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
557     devices_.erase(entry);
558     entry->video_capture_controller.reset();
559     device_task_runner_->PostTask(
560         FROM_HERE,
561         base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
562                    base::Owned(entry)));
563   }
564 }
565 
GetOrCreateDeviceEntry(media::VideoCaptureSessionId capture_session_id)566 VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
567     media::VideoCaptureSessionId capture_session_id) {
568   DCHECK_CURRENTLY_ON(BrowserThread::IO);
569 
570   SessionMap::iterator session_it = sessions_.find(capture_session_id);
571   if (session_it == sessions_.end()) {
572     return NULL;
573   }
574   const MediaStreamDevice& device_info = session_it->second;
575 
576   // Check if another session has already opened this device. If so, just
577   // use that opened device.
578   DeviceEntry* const existing_device =
579       GetDeviceEntryForMediaStreamDevice(device_info);
580   if (existing_device) {
581     DCHECK_EQ(device_info.type, existing_device->stream_type);
582     return existing_device;
583   }
584 
585   scoped_ptr<VideoCaptureController> video_capture_controller(
586       new VideoCaptureController());
587   DeviceEntry* new_device = new DeviceEntry(device_info.type,
588                                             device_info.id,
589                                             video_capture_controller.Pass());
590   devices_.insert(new_device);
591   return new_device;
592 }
593 
FindDeviceInfoById(const std::string & id,DeviceInfos & device_vector)594 VideoCaptureManager::DeviceInfo* VideoCaptureManager::FindDeviceInfoById(
595     const std::string& id,
596     DeviceInfos& device_vector) {
597   for (DeviceInfos::iterator it = device_vector.begin();
598        it != device_vector.end(); ++it) {
599     if (it->name.id() == id)
600       return &(*it);
601   }
602   return NULL;
603 }
604 
SetDesktopCaptureWindowIdOnDeviceThread(DeviceEntry * entry,gfx::NativeViewId window_id)605 void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
606     DeviceEntry* entry,
607     gfx::NativeViewId window_id) {
608   DCHECK(IsOnDeviceThread());
609   DCHECK(entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
610 #if defined(ENABLE_SCREEN_CAPTURE)
611   DesktopCaptureDevice* device =
612       static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
613   device->SetNotificationWindowId(window_id);
614 #endif
615 }
616 
SaveDesktopCaptureWindowIdOnDeviceThread(media::VideoCaptureSessionId session_id,gfx::NativeViewId window_id)617 void VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
618     media::VideoCaptureSessionId session_id,
619     gfx::NativeViewId window_id) {
620   DCHECK(IsOnDeviceThread());
621   DCHECK(notification_window_ids_.find(session_id) ==
622          notification_window_ids_.end());
623   notification_window_ids_[session_id] = window_id;
624 }
625 
626 }  // namespace content
627