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/media/media_internals.h"
18 #include "content/browser/renderer_host/media/video_capture_controller.h"
19 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/desktop_media_id.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/media_stream_request.h"
24 #include "media/base/bind_to_current_loop.h"
25 #include "media/base/scoped_histogram_timer.h"
26 #include "media/video/capture/video_capture_device.h"
27 #include "media/video/capture/video_capture_device_factory.h"
29 #if defined(ENABLE_SCREEN_CAPTURE)
30 #include "content/browser/media/capture/desktop_capture_device.h"
32 #include "content/browser/media/capture/desktop_capture_device_aura.h"
38 // Compares two VideoCaptureFormat by checking smallest frame_size area, then
39 // by _largest_ frame_rate. Used to order a VideoCaptureFormats vector so that
40 // the first entry for a given resolution has the largest frame rate, as needed
41 // by the ConsolidateCaptureFormats() method.
42 bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1,
43 const media::VideoCaptureFormat& format2) {
44 if (format1.frame_size.GetArea() == format2.frame_size.GetArea())
45 return format1.frame_rate > format2.frame_rate;
46 return format1.frame_size.GetArea() < format2.frame_size.GetArea();
49 bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1,
50 const media::VideoCaptureFormat& format2) {
51 return format1.frame_size.GetArea() == format2.frame_size.GetArea();
54 // This function receives a list of capture formats, removes duplicated
55 // resolutions while keeping the highest frame rate for each, and forcing I420
57 void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) {
60 std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller);
61 // Due to the ordering imposed, the largest frame_rate is kept while removing
62 // duplicated resolutions.
63 media::VideoCaptureFormats::iterator last =
64 std::unique(formats->begin(), formats->end(), IsCaptureFormatSizeEqual);
65 formats->erase(last, formats->end());
66 // Mark all formats as I420, since this is what the renderer side will get
67 // anyhow: the actual pixel format is decided at the device level.
68 for (media::VideoCaptureFormats::iterator it = formats->begin();
69 it != formats->end(); ++it) {
70 it->pixel_format = media::PIXEL_FORMAT_I420;
74 // The maximum number of buffers in the capture pipeline. See
75 // VideoCaptureController ctor comments for more details.
76 const int kMaxNumberOfBuffers = 3;
77 const int kMaxNumberOfBuffersForTabCapture = 5;
79 // Used for logging capture events.
80 // Elements in this enum should not be deleted or rearranged; the only
81 // permitted operation is to add new elements before NUM_VIDEO_CAPTURE_EVENT.
82 enum VideoCaptureEvent {
83 VIDEO_CAPTURE_START_CAPTURE = 0,
84 VIDEO_CAPTURE_STOP_CAPTURE_OK = 1,
85 VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR = 2,
86 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE = 3,
87 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB = 4,
88 NUM_VIDEO_CAPTURE_EVENT
91 void LogVideoCaptureEvent(VideoCaptureEvent event) {
92 UMA_HISTOGRAM_ENUMERATION("Media.VideoCaptureManager.Event",
94 NUM_VIDEO_CAPTURE_EVENT);
101 VideoCaptureManager::DeviceEntry::DeviceEntry(
102 MediaStreamType stream_type,
103 const std::string& id,
104 scoped_ptr<VideoCaptureController> controller)
105 : stream_type(stream_type),
107 video_capture_controller(controller.Pass()) {}
109 VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
112 VideoCaptureManager::VideoCaptureManager(
113 scoped_ptr<media::VideoCaptureDeviceFactory> factory)
115 new_capture_session_id_(1),
116 video_capture_device_factory_(factory.Pass()) {
119 VideoCaptureManager::~VideoCaptureManager() {
120 DCHECK(devices_.empty());
123 void VideoCaptureManager::Register(
124 MediaStreamProviderListener* listener,
125 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
126 DCHECK_CURRENTLY_ON(BrowserThread::IO);
128 DCHECK(!device_task_runner_.get());
129 listener_ = listener;
130 device_task_runner_ = device_task_runner;
133 void VideoCaptureManager::Unregister() {
138 void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
139 DCHECK_CURRENTLY_ON(BrowserThread::IO);
140 DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type;
142 DCHECK_EQ(stream_type, MEDIA_DEVICE_VIDEO_CAPTURE);
144 // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument
145 // for another callback to OnDevicesInfoEnumerated() to be run in the current
146 // loop, i.e. IO loop. Pass a timer for UMA histogram collection.
147 base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>
148 devices_enumerated_callback =
149 base::Bind(&VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread,
151 media::BindToCurrentLoop(base::Bind(
152 &VideoCaptureManager::OnDevicesInfoEnumerated,
155 base::Owned(new base::ElapsedTimer()))),
157 devices_info_cache_);
158 // OK to use base::Unretained() since we own the VCDFactory and |this| is
159 // bound in |devices_enumerated_callback|.
160 device_task_runner_->PostTask(FROM_HERE,
161 base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceNames,
162 base::Unretained(video_capture_device_factory_.get()),
163 devices_enumerated_callback));
166 int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
167 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170 // Generate a new id for the session being opened.
171 const media::VideoCaptureSessionId capture_session_id =
172 new_capture_session_id_++;
174 DCHECK(sessions_.find(capture_session_id) == sessions_.end());
175 DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id;
177 // We just save the stream info for processing later.
178 sessions_[capture_session_id] = device_info.device;
180 // Notify our listener asynchronously; this ensures that we return
181 // |capture_session_id| to the caller of this function before using that same
182 // id in a listener event.
183 base::MessageLoop::current()->PostTask(FROM_HERE,
184 base::Bind(&VideoCaptureManager::OnOpened, this,
185 device_info.device.type, capture_session_id));
186 return capture_session_id;
189 void VideoCaptureManager::Close(int capture_session_id) {
190 DCHECK_CURRENTLY_ON(BrowserThread::IO);
192 DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
194 SessionMap::iterator session_it = sessions_.find(capture_session_id);
195 if (session_it == sessions_.end()) {
200 DeviceEntry* const existing_device = GetDeviceEntryForMediaStreamDevice(
202 if (existing_device) {
203 // Remove any client that is still using the session. This is safe to call
204 // even if there are no clients using the session.
205 existing_device->video_capture_controller->StopSession(capture_session_id);
207 // StopSession() may have removed the last client, so we might need to
209 DestroyDeviceEntryIfNoClients(existing_device);
212 // Notify listeners asynchronously, and forget the session.
213 base::MessageLoop::current()->PostTask(FROM_HERE,
214 base::Bind(&VideoCaptureManager::OnClosed, this, session_it->second.type,
215 capture_session_id));
216 sessions_.erase(session_it);
219 void VideoCaptureManager::DoStartDeviceOnDeviceThread(
220 media::VideoCaptureSessionId session_id,
222 const media::VideoCaptureParams& params,
223 scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
224 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
225 DCHECK(IsOnDeviceThread());
227 scoped_ptr<media::VideoCaptureDevice> video_capture_device;
228 switch (entry->stream_type) {
229 case MEDIA_DEVICE_VIDEO_CAPTURE: {
230 // We look up the device id from the renderer in our local enumeration
231 // since the renderer does not have all the information that might be
232 // held in the browser-side VideoCaptureDevice::Name structure.
233 media::VideoCaptureDeviceInfo* found =
234 FindDeviceInfoById(entry->id, devices_info_cache_);
236 video_capture_device =
237 video_capture_device_factory_->Create(found->name);
241 case MEDIA_TAB_VIDEO_CAPTURE: {
242 video_capture_device.reset(
243 WebContentsVideoCaptureDevice::Create(entry->id));
246 case MEDIA_DESKTOP_VIDEO_CAPTURE: {
247 #if defined(ENABLE_SCREEN_CAPTURE)
248 DesktopMediaID id = DesktopMediaID::Parse(entry->id);
249 #if defined(USE_AURA)
250 if (id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
251 video_capture_device.reset(DesktopCaptureDeviceAura::Create(id));
254 if (id.type != DesktopMediaID::TYPE_NONE &&
255 id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
256 video_capture_device = DesktopCaptureDevice::Create(id);
257 if (notification_window_ids_.find(session_id) !=
258 notification_window_ids_.end()) {
259 static_cast<DesktopCaptureDevice*>(video_capture_device.get())
260 ->SetNotificationWindowId(notification_window_ids_[session_id]);
261 VLOG(2) << "Screen capture notification window passed for session "
265 #endif // defined(ENABLE_SCREEN_CAPTURE)
274 if (!video_capture_device) {
275 device_client->OnError("Could not create capture device");
279 video_capture_device->AllocateAndStart(params, device_client.Pass());
280 entry->video_capture_device = video_capture_device.Pass();
283 void VideoCaptureManager::StartCaptureForClient(
284 media::VideoCaptureSessionId session_id,
285 const media::VideoCaptureParams& params,
286 base::ProcessHandle client_render_process,
287 VideoCaptureControllerID client_id,
288 VideoCaptureControllerEventHandler* client_handler,
289 const DoneCB& done_cb) {
290 DCHECK_CURRENTLY_ON(BrowserThread::IO);
291 DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, "
292 << params.requested_format.frame_size.ToString() << ", "
293 << params.requested_format.frame_rate << ", #" << session_id << ")";
295 DeviceEntry* entry = GetOrCreateDeviceEntry(session_id);
297 done_cb.Run(base::WeakPtr<VideoCaptureController>());
301 DCHECK(entry->video_capture_controller);
303 LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE);
305 // First client starts the device.
306 if (entry->video_capture_controller->GetActiveClientCount() == 0) {
307 DVLOG(1) << "VideoCaptureManager starting device (type = "
308 << entry->stream_type << ", id = " << entry->id << ")";
310 device_task_runner_->PostTask(
313 &VideoCaptureManager::DoStartDeviceOnDeviceThread,
318 base::Passed(entry->video_capture_controller->NewDeviceClient())));
320 // Run the callback first, as AddClient() may trigger OnFrameInfo().
321 done_cb.Run(entry->video_capture_controller->GetWeakPtr());
322 entry->video_capture_controller->AddClient(
323 client_id, client_handler, client_render_process, session_id, params);
326 void VideoCaptureManager::StopCaptureForClient(
327 VideoCaptureController* controller,
328 VideoCaptureControllerID client_id,
329 VideoCaptureControllerEventHandler* client_handler,
330 bool aborted_due_to_error) {
331 DCHECK_CURRENTLY_ON(BrowserThread::IO);
333 DCHECK(client_handler);
335 DeviceEntry* entry = GetDeviceEntryForController(controller);
340 if (!aborted_due_to_error) {
341 if (controller->has_received_frames()) {
342 LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_OK);
343 } else if (entry->stream_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
344 LogVideoCaptureEvent(
345 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE);
347 LogVideoCaptureEvent(
348 VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB);
351 LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR);
352 SessionMap::iterator it;
353 for (it = sessions_.begin(); it != sessions_.end(); ++it) {
354 if (it->second.type == entry->stream_type &&
355 it->second.id == entry->id) {
356 listener_->Aborted(it->second.type, it->first);
362 // Detach client from controller.
363 media::VideoCaptureSessionId session_id =
364 controller->RemoveClient(client_id, client_handler);
365 DVLOG(1) << "VideoCaptureManager::StopCaptureForClient, session_id = "
368 // If controller has no more clients, delete controller and device.
369 DestroyDeviceEntryIfNoClients(entry);
372 void VideoCaptureManager::PauseCaptureForClient(
373 VideoCaptureController* controller,
374 VideoCaptureControllerID client_id,
375 VideoCaptureControllerEventHandler* client_handler) {
376 DCHECK_CURRENTLY_ON(BrowserThread::IO);
378 DCHECK(client_handler);
379 DeviceEntry* entry = GetDeviceEntryForController(controller);
385 // We only pause the MEDIA_DEVICE_VIDEO_CAPTURE entry to release camera to
387 if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
390 controller->PauseOrResumeClient(client_id, client_handler, true);
391 if (controller->GetActiveClientCount() != 0)
394 // There is no more client, release the camera.
395 device_task_runner_->PostTask(
397 base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
398 base::Unretained(entry)));
401 void VideoCaptureManager::ResumeCaptureForClient(
402 media::VideoCaptureSessionId session_id,
403 const media::VideoCaptureParams& params,
404 VideoCaptureController* controller,
405 VideoCaptureControllerID client_id,
406 VideoCaptureControllerEventHandler* client_handler) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO);
409 DCHECK(client_handler);
411 DeviceEntry* entry = GetDeviceEntryForController(controller);
417 // We only pause/resume the MEDIA_DEVICE_VIDEO_CAPTURE entry.
418 if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
421 controller->PauseOrResumeClient(client_id, client_handler, false);
422 if (controller->GetActiveClientCount() != 1)
425 // This is first active client, allocate the camera.
426 device_task_runner_->PostTask(
429 &VideoCaptureManager::DoStartDeviceOnDeviceThread,
434 base::Passed(entry->video_capture_controller->NewDeviceClient())));
437 bool VideoCaptureManager::GetDeviceSupportedFormats(
438 media::VideoCaptureSessionId capture_session_id,
439 media::VideoCaptureFormats* supported_formats) {
440 DCHECK_CURRENTLY_ON(BrowserThread::IO);
441 DCHECK(supported_formats->empty());
443 SessionMap::iterator it = sessions_.find(capture_session_id);
444 if (it == sessions_.end())
446 DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
448 // Return all available formats of the device, regardless its started state.
449 media::VideoCaptureDeviceInfo* existing_device =
450 FindDeviceInfoById(it->second.id, devices_info_cache_);
452 *supported_formats = existing_device->supported_formats;
456 bool VideoCaptureManager::GetDeviceFormatsInUse(
457 media::VideoCaptureSessionId capture_session_id,
458 media::VideoCaptureFormats* formats_in_use) {
459 DCHECK_CURRENTLY_ON(BrowserThread::IO);
460 DCHECK(formats_in_use->empty());
462 SessionMap::iterator it = sessions_.find(capture_session_id);
463 if (it == sessions_.end())
465 DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name;
467 // Return the currently in-use format(s) of the device, if it's started.
468 DeviceEntry* device_in_use =
469 GetDeviceEntryForMediaStreamDevice(it->second);
471 // Currently only one format-in-use is supported at the VCC level.
472 formats_in_use->push_back(
473 device_in_use->video_capture_controller->GetVideoCaptureFormat());
478 void VideoCaptureManager::SetDesktopCaptureWindowId(
479 media::VideoCaptureSessionId session_id,
480 gfx::NativeViewId window_id) {
481 DCHECK_CURRENTLY_ON(BrowserThread::IO);
482 VLOG(2) << "SetDesktopCaptureWindowId called for session " << session_id;
484 SessionMap::iterator session_it = sessions_.find(session_id);
485 if (session_it == sessions_.end()) {
486 VLOG(2) << "Session not found, will save the notification window.";
487 device_task_runner_->PostTask(
490 &VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread,
497 DeviceEntry* const existing_device =
498 GetDeviceEntryForMediaStreamDevice(session_it->second);
499 if (!existing_device) {
500 VLOG(2) << "Failed to find an existing device.";
504 DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type);
505 DesktopMediaID id = DesktopMediaID::Parse(existing_device->id);
506 if (id.type == DesktopMediaID::TYPE_NONE ||
507 id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
508 VLOG(2) << "Video capture device type mismatch.";
512 device_task_runner_->PostTask(
514 base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread,
520 void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
521 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
522 DCHECK(IsOnDeviceThread());
523 if (entry->video_capture_device) {
524 entry->video_capture_device->StopAndDeAllocate();
526 entry->video_capture_device.reset();
529 void VideoCaptureManager::OnOpened(
530 MediaStreamType stream_type,
531 media::VideoCaptureSessionId capture_session_id) {
532 DCHECK_CURRENTLY_ON(BrowserThread::IO);
534 // Listener has been removed.
537 listener_->Opened(stream_type, capture_session_id);
540 void VideoCaptureManager::OnClosed(
541 MediaStreamType stream_type,
542 media::VideoCaptureSessionId capture_session_id) {
543 DCHECK_CURRENTLY_ON(BrowserThread::IO);
545 // Listener has been removed.
548 listener_->Closed(stream_type, capture_session_id);
551 void VideoCaptureManager::OnDevicesInfoEnumerated(
552 MediaStreamType stream_type,
553 base::ElapsedTimer* timer,
554 const media::VideoCaptureDeviceInfos& new_devices_info_cache) {
555 DCHECK_CURRENTLY_ON(BrowserThread::IO);
557 "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime",
560 // Listener has been removed.
563 devices_info_cache_ = new_devices_info_cache;
565 MediaInternals::GetInstance()->UpdateVideoCaptureDeviceCapabilities(
566 devices_info_cache_);
568 // Walk the |devices_info_cache_| and transform from VCD::Name to
569 // StreamDeviceInfo for return purposes.
570 StreamDeviceInfoArray devices;
571 for (const auto& it : devices_info_cache_) {
572 devices.push_back(StreamDeviceInfo(
573 stream_type, it.name.GetNameAndModel(), it.name.id()));
575 listener_->DevicesEnumerated(stream_type, devices);
578 bool VideoCaptureManager::IsOnDeviceThread() const {
579 return device_task_runner_->BelongsToCurrentThread();
582 void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
583 base::Callback<void(const media::VideoCaptureDeviceInfos&)>
584 on_devices_enumerated_callback,
585 MediaStreamType stream_type,
586 const media::VideoCaptureDeviceInfos& old_device_info_cache,
587 scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot) {
588 DCHECK(IsOnDeviceThread());
589 // Construct |new_devices_info_cache| with the cached devices that are still
590 // present in the system, and remove their names from |names_snapshot|, so we
591 // keep there the truly new devices.
592 media::VideoCaptureDeviceInfos new_devices_info_cache;
593 for (const auto& device_info : old_device_info_cache) {
594 for (media::VideoCaptureDevice::Names::iterator it =
595 names_snapshot->begin(); it != names_snapshot->end(); ++it) {
596 if (device_info.name.id() == it->id()) {
597 new_devices_info_cache.push_back(device_info);
598 names_snapshot->erase(it);
604 // Get the supported capture formats for the new devices in |names_snapshot|.
605 for (const auto& it : *names_snapshot) {
606 media::VideoCaptureDeviceInfo device_info(it, media::VideoCaptureFormats());
607 video_capture_device_factory_->GetDeviceSupportedFormats(
608 it, &(device_info.supported_formats));
609 ConsolidateCaptureFormats(&device_info.supported_formats);
610 new_devices_info_cache.push_back(device_info);
613 on_devices_enumerated_callback.Run(new_devices_info_cache);
616 VideoCaptureManager::DeviceEntry*
617 VideoCaptureManager::GetDeviceEntryForMediaStreamDevice(
618 const MediaStreamDevice& device_info) {
619 DCHECK_CURRENTLY_ON(BrowserThread::IO);
621 for (DeviceEntries::iterator it = devices_.begin();
622 it != devices_.end(); ++it) {
623 DeviceEntry* device = *it;
624 if (device_info.type == device->stream_type &&
625 device_info.id == device->id) {
632 VideoCaptureManager::DeviceEntry*
633 VideoCaptureManager::GetDeviceEntryForController(
634 const VideoCaptureController* controller) const {
635 // Look up |controller| in |devices_|.
636 for (DeviceEntries::const_iterator it = devices_.begin();
637 it != devices_.end(); ++it) {
638 if ((*it)->video_capture_controller.get() == controller) {
645 void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
646 DCHECK_CURRENTLY_ON(BrowserThread::IO);
647 // Removal of the last client stops the device.
648 if (entry->video_capture_controller->GetClientCount() == 0) {
649 DVLOG(1) << "VideoCaptureManager stopping device (type = "
650 << entry->stream_type << ", id = " << entry->id << ")";
652 // The DeviceEntry is removed from |devices_| immediately. The controller is
653 // deleted immediately, and the device is freed asynchronously. After this
654 // point, subsequent requests to open this same device ID will create a new
655 // DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
656 devices_.erase(entry);
657 entry->video_capture_controller.reset();
658 device_task_runner_->PostTask(
660 base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
661 base::Owned(entry)));
665 VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
666 media::VideoCaptureSessionId capture_session_id) {
667 DCHECK_CURRENTLY_ON(BrowserThread::IO);
669 SessionMap::iterator session_it = sessions_.find(capture_session_id);
670 if (session_it == sessions_.end()) {
673 const MediaStreamDevice& device_info = session_it->second;
675 // Check if another session has already opened this device. If so, just
676 // use that opened device.
677 DeviceEntry* const existing_device =
678 GetDeviceEntryForMediaStreamDevice(device_info);
679 if (existing_device) {
680 DCHECK_EQ(device_info.type, existing_device->stream_type);
681 return existing_device;
684 const int max_buffers = device_info.type == MEDIA_TAB_VIDEO_CAPTURE ?
685 kMaxNumberOfBuffersForTabCapture : kMaxNumberOfBuffers;
686 scoped_ptr<VideoCaptureController> video_capture_controller(
687 new VideoCaptureController(max_buffers));
688 DeviceEntry* new_device = new DeviceEntry(device_info.type,
690 video_capture_controller.Pass());
691 devices_.insert(new_device);
695 media::VideoCaptureDeviceInfo* VideoCaptureManager::FindDeviceInfoById(
696 const std::string& id,
697 media::VideoCaptureDeviceInfos& device_vector) {
698 for (auto& it : device_vector) {
699 if (it.name.id() == id)
705 void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
707 gfx::NativeViewId window_id) {
708 DCHECK(IsOnDeviceThread());
709 DCHECK(entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
710 #if defined(ENABLE_SCREEN_CAPTURE)
711 DesktopCaptureDevice* device =
712 static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
713 device->SetNotificationWindowId(window_id);
714 VLOG(2) << "Screen capture notification window passed on device thread.";
718 void VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
719 media::VideoCaptureSessionId session_id,
720 gfx::NativeViewId window_id) {
721 DCHECK(IsOnDeviceThread());
722 DCHECK(notification_window_ids_.find(session_id) ==
723 notification_window_ids_.end());
724 notification_window_ids_[session_id] = window_id;
725 VLOG(2) << "Screen capture notification window saved for session "
726 << session_id << " on device thread.";
729 } // namespace content