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/video_capture_manager.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"
28 #if defined(ENABLE_SCREEN_CAPTURE)
29 #include "content/browser/media/capture/desktop_capture_device.h"
31 #include "content/browser/media/capture/desktop_capture_device_aura.h"
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.
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();
48 bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat
& format1
,
49 const media::VideoCaptureFormat
& format2
) {
50 return format1
.frame_size
.GetArea() == format2
.frame_size
.GetArea();
53 // This function receives a list of capture formats, removes duplicated
54 // resolutions while keeping the highest frame rate for each, and forcing I420
56 void ConsolidateCaptureFormats(media::VideoCaptureFormats
* formats
) {
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
;
73 // The maximum number of buffers in the capture pipeline. See
74 // VideoCaptureController ctor comments for more details.
75 const int kMaxNumberOfBuffers
= 3;
76 const int kMaxNumberOfBuffersForTabCapture
= 5;
78 // Used for logging capture events.
79 // Elements in this enum should not be deleted or rearranged; the only
80 // permitted operation is to add new elements before NUM_VIDEO_CAPTURE_EVENT.
81 enum VideoCaptureEvent
{
82 VIDEO_CAPTURE_EVENT_START_CAPTURE
= 0,
83 VIDEO_CAPTURE_EVENT_STOP_CAPTURE_NORMAL
= 1,
84 VIDEO_CAPTURE_EVENT_STOP_CAPTURE_DUE_TO_ERROR
= 2,
85 NUM_VIDEO_CAPTURE_EVENT
88 void LogVideoCaptureEvent(VideoCaptureEvent event
) {
89 UMA_HISTOGRAM_ENUMERATION("Media.VideoCaptureManager.Event",
91 NUM_VIDEO_CAPTURE_EVENT
);
98 VideoCaptureManager::DeviceEntry::DeviceEntry(
99 MediaStreamType stream_type
,
100 const std::string
& id
,
101 scoped_ptr
<VideoCaptureController
> controller
)
102 : stream_type(stream_type
),
104 video_capture_controller(controller
.Pass()) {}
106 VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
108 VideoCaptureManager::DeviceInfo::DeviceInfo() {}
110 VideoCaptureManager::DeviceInfo::DeviceInfo(
111 const media::VideoCaptureDevice::Name
& name
,
112 const media::VideoCaptureFormats
& supported_formats
)
114 supported_formats(supported_formats
) {}
116 VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
118 VideoCaptureManager::VideoCaptureManager(
119 scoped_ptr
<media::VideoCaptureDeviceFactory
> factory
)
121 new_capture_session_id_(1),
122 video_capture_device_factory_(factory
.Pass()) {
125 VideoCaptureManager::~VideoCaptureManager() {
126 DCHECK(devices_
.empty());
129 void VideoCaptureManager::Register(
130 MediaStreamProviderListener
* listener
,
131 const scoped_refptr
<base::SingleThreadTaskRunner
>& device_task_runner
) {
132 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
134 DCHECK(!device_task_runner_
.get());
135 listener_
= listener
;
136 device_task_runner_
= device_task_runner
;
139 void VideoCaptureManager::Unregister() {
144 void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type
) {
145 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
146 DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type
;
148 DCHECK_EQ(stream_type
, MEDIA_DEVICE_VIDEO_CAPTURE
);
150 // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument
151 // for another callback to OnDevicesInfoEnumerated() to be run in the current
152 // loop, i.e. IO loop. Pass a timer for UMA histogram collection.
153 base::Callback
<void(scoped_ptr
<media::VideoCaptureDevice::Names
>)>
154 devices_enumerated_callback
=
155 base::Bind(&VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread
,
157 media::BindToCurrentLoop(base::Bind(
158 &VideoCaptureManager::OnDevicesInfoEnumerated
,
161 base::Owned(new base::ElapsedTimer()))),
163 devices_info_cache_
);
164 // OK to use base::Unretained() since we own the VCDFactory and |this| is
165 // bound in |devices_enumerated_callback|.
166 device_task_runner_
->PostTask(FROM_HERE
,
167 base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceNames
,
168 base::Unretained(video_capture_device_factory_
.get()),
169 devices_enumerated_callback
));
172 int VideoCaptureManager::Open(const StreamDeviceInfo
& device_info
) {
173 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
176 // Generate a new id for the session being opened.
177 const media::VideoCaptureSessionId capture_session_id
=
178 new_capture_session_id_
++;
180 DCHECK(sessions_
.find(capture_session_id
) == sessions_
.end());
181 DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id
;
183 // We just save the stream info for processing later.
184 sessions_
[capture_session_id
] = device_info
.device
;
186 // Notify our listener asynchronously; this ensures that we return
187 // |capture_session_id| to the caller of this function before using that same
188 // id in a listener event.
189 base::MessageLoop::current()->PostTask(FROM_HERE
,
190 base::Bind(&VideoCaptureManager::OnOpened
, this,
191 device_info
.device
.type
, capture_session_id
));
192 return capture_session_id
;
195 void VideoCaptureManager::Close(int capture_session_id
) {
196 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
198 DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id
;
200 SessionMap::iterator session_it
= sessions_
.find(capture_session_id
);
201 if (session_it
== sessions_
.end()) {
206 DeviceEntry
* const existing_device
= GetDeviceEntryForMediaStreamDevice(
208 if (existing_device
) {
209 // Remove any client that is still using the session. This is safe to call
210 // even if there are no clients using the session.
211 existing_device
->video_capture_controller
->StopSession(capture_session_id
);
213 // StopSession() may have removed the last client, so we might need to
215 DestroyDeviceEntryIfNoClients(existing_device
);
218 // Notify listeners asynchronously, and forget the session.
219 base::MessageLoop::current()->PostTask(FROM_HERE
,
220 base::Bind(&VideoCaptureManager::OnClosed
, this, session_it
->second
.type
,
221 capture_session_id
));
222 sessions_
.erase(session_it
);
225 void VideoCaptureManager::DoStartDeviceOnDeviceThread(
226 media::VideoCaptureSessionId session_id
,
228 const media::VideoCaptureParams
& params
,
229 scoped_ptr
<media::VideoCaptureDevice::Client
> device_client
) {
230 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
231 DCHECK(IsOnDeviceThread());
233 scoped_ptr
<media::VideoCaptureDevice
> video_capture_device
;
234 switch (entry
->stream_type
) {
235 case MEDIA_DEVICE_VIDEO_CAPTURE
: {
236 // We look up the device id from the renderer in our local enumeration
237 // since the renderer does not have all the information that might be
238 // held in the browser-side VideoCaptureDevice::Name structure.
239 DeviceInfo
* found
= FindDeviceInfoById(entry
->id
, devices_info_cache_
);
241 video_capture_device
=
242 video_capture_device_factory_
->Create(found
->name
);
246 case MEDIA_TAB_VIDEO_CAPTURE
: {
247 video_capture_device
.reset(
248 WebContentsVideoCaptureDevice::Create(entry
->id
));
251 case MEDIA_DESKTOP_VIDEO_CAPTURE
: {
252 #if defined(ENABLE_SCREEN_CAPTURE)
253 DesktopMediaID id
= DesktopMediaID::Parse(entry
->id
);
254 #if defined(USE_AURA)
255 if (id
.type
== DesktopMediaID::TYPE_AURA_WINDOW
) {
256 video_capture_device
.reset(DesktopCaptureDeviceAura::Create(id
));
259 if (id
.type
!= DesktopMediaID::TYPE_NONE
&&
260 id
.type
!= DesktopMediaID::TYPE_AURA_WINDOW
) {
261 video_capture_device
= DesktopCaptureDevice::Create(id
);
262 if (notification_window_ids_
.find(session_id
) !=
263 notification_window_ids_
.end()) {
264 static_cast<DesktopCaptureDevice
*>(video_capture_device
.get())
265 ->SetNotificationWindowId(notification_window_ids_
[session_id
]);
268 #endif // defined(ENABLE_SCREEN_CAPTURE)
277 if (!video_capture_device
) {
278 device_client
->OnError("Could not create capture device");
282 video_capture_device
->AllocateAndStart(params
, device_client
.Pass());
283 entry
->video_capture_device
= video_capture_device
.Pass();
286 void VideoCaptureManager::StartCaptureForClient(
287 media::VideoCaptureSessionId session_id
,
288 const media::VideoCaptureParams
& params
,
289 base::ProcessHandle client_render_process
,
290 VideoCaptureControllerID client_id
,
291 VideoCaptureControllerEventHandler
* client_handler
,
292 const DoneCB
& done_cb
) {
293 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
294 DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, "
295 << params
.requested_format
.frame_size
.ToString() << ", "
296 << params
.requested_format
.frame_rate
<< ", #" << session_id
<< ")";
298 DeviceEntry
* entry
= GetOrCreateDeviceEntry(session_id
);
300 done_cb
.Run(base::WeakPtr
<VideoCaptureController
>());
304 DCHECK(entry
->video_capture_controller
);
306 LogVideoCaptureEvent(VIDEO_CAPTURE_EVENT_START_CAPTURE
);
308 // First client starts the device.
309 if (entry
->video_capture_controller
->GetClientCount() == 0) {
310 DVLOG(1) << "VideoCaptureManager starting device (type = "
311 << entry
->stream_type
<< ", id = " << entry
->id
<< ")";
313 device_task_runner_
->PostTask(
316 &VideoCaptureManager::DoStartDeviceOnDeviceThread
,
321 base::Passed(entry
->video_capture_controller
->NewDeviceClient())));
323 // Run the callback first, as AddClient() may trigger OnFrameInfo().
324 done_cb
.Run(entry
->video_capture_controller
->GetWeakPtr());
325 entry
->video_capture_controller
->AddClient(
326 client_id
, client_handler
, client_render_process
, session_id
, params
);
329 void VideoCaptureManager::StopCaptureForClient(
330 VideoCaptureController
* controller
,
331 VideoCaptureControllerID client_id
,
332 VideoCaptureControllerEventHandler
* client_handler
,
333 bool aborted_due_to_error
) {
334 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
336 DCHECK(client_handler
);
338 LogVideoCaptureEvent(aborted_due_to_error
?
339 VIDEO_CAPTURE_EVENT_STOP_CAPTURE_DUE_TO_ERROR
:
340 VIDEO_CAPTURE_EVENT_STOP_CAPTURE_NORMAL
);
342 DeviceEntry
* entry
= GetDeviceEntryForController(controller
);
347 if (aborted_due_to_error
) {
348 SessionMap::iterator it
;
349 for (it
= sessions_
.begin(); it
!= sessions_
.end(); ++it
) {
350 if (it
->second
.type
== entry
->stream_type
&&
351 it
->second
.id
== entry
->id
) {
352 listener_
->Aborted(it
->second
.type
, it
->first
);
358 // Detach client from controller.
359 media::VideoCaptureSessionId session_id
=
360 controller
->RemoveClient(client_id
, client_handler
);
361 DVLOG(1) << "VideoCaptureManager::StopCaptureForClient, session_id = "
364 // If controller has no more clients, delete controller and device.
365 DestroyDeviceEntryIfNoClients(entry
);
368 bool VideoCaptureManager::GetDeviceSupportedFormats(
369 media::VideoCaptureSessionId capture_session_id
,
370 media::VideoCaptureFormats
* supported_formats
) {
371 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
372 DCHECK(supported_formats
->empty());
374 SessionMap::iterator it
= sessions_
.find(capture_session_id
);
375 if (it
== sessions_
.end())
377 DVLOG(1) << "GetDeviceSupportedFormats for device: " << it
->second
.name
;
379 // Return all available formats of the device, regardless its started state.
380 DeviceInfo
* existing_device
=
381 FindDeviceInfoById(it
->second
.id
, devices_info_cache_
);
383 *supported_formats
= existing_device
->supported_formats
;
387 bool VideoCaptureManager::GetDeviceFormatsInUse(
388 media::VideoCaptureSessionId capture_session_id
,
389 media::VideoCaptureFormats
* formats_in_use
) {
390 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
391 DCHECK(formats_in_use
->empty());
393 SessionMap::iterator it
= sessions_
.find(capture_session_id
);
394 if (it
== sessions_
.end())
396 DVLOG(1) << "GetDeviceFormatsInUse for device: " << it
->second
.name
;
398 // Return the currently in-use format(s) of the device, if it's started.
399 DeviceEntry
* device_in_use
=
400 GetDeviceEntryForMediaStreamDevice(it
->second
);
402 // Currently only one format-in-use is supported at the VCC level.
403 formats_in_use
->push_back(
404 device_in_use
->video_capture_controller
->GetVideoCaptureFormat());
409 void VideoCaptureManager::SetDesktopCaptureWindowId(
410 media::VideoCaptureSessionId session_id
,
411 gfx::NativeViewId window_id
) {
412 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
413 SessionMap::iterator session_it
= sessions_
.find(session_id
);
414 if (session_it
== sessions_
.end()) {
415 device_task_runner_
->PostTask(
418 &VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread
,
425 DeviceEntry
* const existing_device
=
426 GetDeviceEntryForMediaStreamDevice(session_it
->second
);
427 if (!existing_device
)
430 DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE
, existing_device
->stream_type
);
431 DesktopMediaID id
= DesktopMediaID::Parse(existing_device
->id
);
432 if (id
.type
== DesktopMediaID::TYPE_NONE
||
433 id
.type
== DesktopMediaID::TYPE_AURA_WINDOW
) {
437 device_task_runner_
->PostTask(
439 base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread
,
445 void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry
* entry
) {
446 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
447 DCHECK(IsOnDeviceThread());
448 if (entry
->video_capture_device
) {
449 entry
->video_capture_device
->StopAndDeAllocate();
451 entry
->video_capture_device
.reset();
454 void VideoCaptureManager::OnOpened(
455 MediaStreamType stream_type
,
456 media::VideoCaptureSessionId capture_session_id
) {
457 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
459 // Listener has been removed.
462 listener_
->Opened(stream_type
, capture_session_id
);
465 void VideoCaptureManager::OnClosed(
466 MediaStreamType stream_type
,
467 media::VideoCaptureSessionId capture_session_id
) {
468 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
470 // Listener has been removed.
473 listener_
->Closed(stream_type
, capture_session_id
);
476 void VideoCaptureManager::OnDevicesInfoEnumerated(
477 MediaStreamType stream_type
,
478 base::ElapsedTimer
* timer
,
479 const DeviceInfos
& new_devices_info_cache
) {
480 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
482 "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime",
485 // Listener has been removed.
488 devices_info_cache_
= new_devices_info_cache
;
490 // Walk the |devices_info_cache_| and transform from VCD::Name to
491 // StreamDeviceInfo for return purposes.
492 StreamDeviceInfoArray devices
;
493 for (DeviceInfos::const_iterator it
= devices_info_cache_
.begin();
494 it
!= devices_info_cache_
.end(); ++it
) {
495 devices
.push_back(StreamDeviceInfo(
496 stream_type
, it
->name
.GetNameAndModel(), it
->name
.id()));
498 listener_
->DevicesEnumerated(stream_type
, devices
);
501 bool VideoCaptureManager::IsOnDeviceThread() const {
502 return device_task_runner_
->BelongsToCurrentThread();
505 void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
506 base::Callback
<void(const DeviceInfos
&)> on_devices_enumerated_callback
,
507 MediaStreamType stream_type
,
508 const DeviceInfos
& old_device_info_cache
,
509 scoped_ptr
<media::VideoCaptureDevice::Names
> names_snapshot
) {
510 DCHECK(IsOnDeviceThread());
511 // Construct |new_devices_info_cache| with the cached devices that are still
512 // present in the system, and remove their names from |names_snapshot|, so we
513 // keep there the truly new devices.
514 DeviceInfos new_devices_info_cache
;
515 for (DeviceInfos::const_iterator it_device_info
=
516 old_device_info_cache
.begin();
517 it_device_info
!= old_device_info_cache
.end(); ++it_device_info
) {
518 for (media::VideoCaptureDevice::Names::iterator it
=
519 names_snapshot
->begin();
520 it
!= names_snapshot
->end(); ++it
) {
521 if (it_device_info
->name
.id() == it
->id()) {
522 new_devices_info_cache
.push_back(*it_device_info
);
523 names_snapshot
->erase(it
);
529 // Get the supported capture formats for the new devices in |names_snapshot|.
530 for (media::VideoCaptureDevice::Names::const_iterator it
=
531 names_snapshot
->begin();
532 it
!= names_snapshot
->end(); ++it
) {
533 media::VideoCaptureFormats supported_formats
;
534 DeviceInfo
device_info(*it
, media::VideoCaptureFormats());
535 video_capture_device_factory_
->GetDeviceSupportedFormats(
536 *it
, &(device_info
.supported_formats
));
537 ConsolidateCaptureFormats(&device_info
.supported_formats
);
538 new_devices_info_cache
.push_back(device_info
);
541 on_devices_enumerated_callback
.Run(new_devices_info_cache
);
544 VideoCaptureManager::DeviceEntry
*
545 VideoCaptureManager::GetDeviceEntryForMediaStreamDevice(
546 const MediaStreamDevice
& device_info
) {
547 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
549 for (DeviceEntries::iterator it
= devices_
.begin();
550 it
!= devices_
.end(); ++it
) {
551 DeviceEntry
* device
= *it
;
552 if (device_info
.type
== device
->stream_type
&&
553 device_info
.id
== device
->id
) {
560 VideoCaptureManager::DeviceEntry
*
561 VideoCaptureManager::GetDeviceEntryForController(
562 const VideoCaptureController
* controller
) const {
563 // Look up |controller| in |devices_|.
564 for (DeviceEntries::const_iterator it
= devices_
.begin();
565 it
!= devices_
.end(); ++it
) {
566 if ((*it
)->video_capture_controller
.get() == controller
) {
573 void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry
* entry
) {
574 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
575 // Removal of the last client stops the device.
576 if (entry
->video_capture_controller
->GetClientCount() == 0) {
577 DVLOG(1) << "VideoCaptureManager stopping device (type = "
578 << entry
->stream_type
<< ", id = " << entry
->id
<< ")";
580 // The DeviceEntry is removed from |devices_| immediately. The controller is
581 // deleted immediately, and the device is freed asynchronously. After this
582 // point, subsequent requests to open this same device ID will create a new
583 // DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
584 devices_
.erase(entry
);
585 entry
->video_capture_controller
.reset();
586 device_task_runner_
->PostTask(
588 base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread
, this,
589 base::Owned(entry
)));
593 VideoCaptureManager::DeviceEntry
* VideoCaptureManager::GetOrCreateDeviceEntry(
594 media::VideoCaptureSessionId capture_session_id
) {
595 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
597 SessionMap::iterator session_it
= sessions_
.find(capture_session_id
);
598 if (session_it
== sessions_
.end()) {
601 const MediaStreamDevice
& device_info
= session_it
->second
;
603 // Check if another session has already opened this device. If so, just
604 // use that opened device.
605 DeviceEntry
* const existing_device
=
606 GetDeviceEntryForMediaStreamDevice(device_info
);
607 if (existing_device
) {
608 DCHECK_EQ(device_info
.type
, existing_device
->stream_type
);
609 return existing_device
;
612 const int max_buffers
= device_info
.type
== MEDIA_TAB_VIDEO_CAPTURE
?
613 kMaxNumberOfBuffersForTabCapture
: kMaxNumberOfBuffers
;
614 scoped_ptr
<VideoCaptureController
> video_capture_controller(
615 new VideoCaptureController(max_buffers
));
616 DeviceEntry
* new_device
= new DeviceEntry(device_info
.type
,
618 video_capture_controller
.Pass());
619 devices_
.insert(new_device
);
623 VideoCaptureManager::DeviceInfo
* VideoCaptureManager::FindDeviceInfoById(
624 const std::string
& id
,
625 DeviceInfos
& device_vector
) {
626 for (DeviceInfos::iterator it
= device_vector
.begin();
627 it
!= device_vector
.end(); ++it
) {
628 if (it
->name
.id() == id
)
634 void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
636 gfx::NativeViewId window_id
) {
637 DCHECK(IsOnDeviceThread());
638 DCHECK(entry
->stream_type
== MEDIA_DESKTOP_VIDEO_CAPTURE
);
639 #if defined(ENABLE_SCREEN_CAPTURE)
640 DesktopCaptureDevice
* device
=
641 static_cast<DesktopCaptureDevice
*>(entry
->video_capture_device
.get());
642 device
->SetNotificationWindowId(window_id
);
646 void VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
647 media::VideoCaptureSessionId session_id
,
648 gfx::NativeViewId window_id
) {
649 DCHECK(IsOnDeviceThread());
650 DCHECK(notification_window_ids_
.find(session_id
) ==
651 notification_window_ids_
.end());
652 notification_window_ids_
[session_id
] = window_id
;
655 } // namespace content