Home | History | Annotate | Download | only in media
      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.
     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 
     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.
     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 
     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 
     85 VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
     86 
     87 VideoCaptureManager::DeviceInfo::DeviceInfo() {}
     88 
     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 
     95 VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
     96 
     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 
    104 VideoCaptureManager::~VideoCaptureManager() {
    105   DCHECK(devices_.empty());
    106 }
    107 
    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 
    118 void VideoCaptureManager::Unregister() {
    119   DCHECK(listener_);
    120   listener_ = NULL;
    121 }
    122 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    474 bool VideoCaptureManager::IsOnDeviceThread() const {
    475   return device_task_runner_->BelongsToCurrentThread();
    476 }
    477 
    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*
    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*
    534 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 
    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 
    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 
    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 
    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 
    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