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/command_line.h"
     11 #include "base/logging.h"
     12 #include "base/stl_util.h"
     13 #include "base/threading/sequenced_worker_pool.h"
     14 #include "content/browser/renderer_host/media/video_capture_controller.h"
     15 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
     16 #include "content/browser/renderer_host/media/web_contents_video_capture_device.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/common/content_switches.h"
     19 #include "content/public/common/desktop_media_id.h"
     20 #include "content/public/common/media_stream_request.h"
     21 #include "media/base/scoped_histogram_timer.h"
     22 #include "media/video/capture/fake_video_capture_device.h"
     23 #include "media/video/capture/video_capture_device.h"
     24 
     25 #if defined(ENABLE_SCREEN_CAPTURE)
     26 #include "content/browser/renderer_host/media/desktop_capture_device.h"
     27 #endif
     28 
     29 namespace content {
     30 
     31 // Starting id for the first capture session.
     32 // VideoCaptureManager::kStartOpenSessionId is used as default id without
     33 // explicitly calling open device.
     34 enum { kFirstSessionId = VideoCaptureManager::kStartOpenSessionId + 1 };
     35 
     36 struct VideoCaptureManager::Controller {
     37   Controller(
     38       VideoCaptureController* vc_controller,
     39       VideoCaptureControllerEventHandler* handler)
     40       : controller(vc_controller),
     41         ready_to_delete(false) {
     42     handlers.push_front(handler);
     43   }
     44   ~Controller() {}
     45 
     46   scoped_refptr<VideoCaptureController> controller;
     47   bool ready_to_delete;
     48   Handlers handlers;
     49 };
     50 
     51 VideoCaptureManager::VideoCaptureManager()
     52     : listener_(NULL),
     53       new_capture_session_id_(kFirstSessionId),
     54       use_fake_device_(false) {
     55 }
     56 
     57 VideoCaptureManager::~VideoCaptureManager() {
     58   DCHECK(devices_.empty());
     59   DCHECK(controllers_.empty());
     60 }
     61 
     62 void VideoCaptureManager::Register(MediaStreamProviderListener* listener,
     63                                    base::MessageLoopProxy* device_thread_loop) {
     64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     65   DCHECK(!listener_);
     66   DCHECK(!device_loop_.get());
     67   listener_ = listener;
     68   device_loop_ = device_thread_loop;
     69 }
     70 
     71 void VideoCaptureManager::Unregister() {
     72   DCHECK(listener_);
     73   listener_ = NULL;
     74 }
     75 
     76 void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
     77   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     78   DCHECK(listener_);
     79   device_loop_->PostTask(
     80       FROM_HERE,
     81       base::Bind(&VideoCaptureManager::OnEnumerateDevices, this, stream_type));
     82 }
     83 
     84 int VideoCaptureManager::Open(const StreamDeviceInfo& device) {
     85   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     86   DCHECK(listener_);
     87 
     88   // Generate a new id for this device.
     89   int video_capture_session_id = new_capture_session_id_++;
     90 
     91   device_loop_->PostTask(
     92       FROM_HERE,
     93       base::Bind(&VideoCaptureManager::OnOpen, this, video_capture_session_id,
     94                  device));
     95 
     96   return video_capture_session_id;
     97 }
     98 
     99 void VideoCaptureManager::Close(int capture_session_id) {
    100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    101   DCHECK(listener_);
    102   DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
    103   device_loop_->PostTask(
    104       FROM_HERE,
    105       base::Bind(&VideoCaptureManager::OnClose, this, capture_session_id));
    106 }
    107 
    108 void VideoCaptureManager::Start(
    109     const media::VideoCaptureParams& capture_params,
    110     media::VideoCaptureDevice::EventHandler* video_capture_receiver) {
    111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    112   device_loop_->PostTask(
    113       FROM_HERE,
    114       base::Bind(&VideoCaptureManager::OnStart, this, capture_params,
    115                  video_capture_receiver));
    116 }
    117 
    118 void VideoCaptureManager::Stop(
    119     const media::VideoCaptureSessionId& capture_session_id,
    120     base::Closure stopped_cb) {
    121   DVLOG(1) << "VideoCaptureManager::Stop, id " << capture_session_id;
    122   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    123   device_loop_->PostTask(
    124       FROM_HERE,
    125       base::Bind(&VideoCaptureManager::OnStop, this, capture_session_id,
    126                  stopped_cb));
    127 }
    128 
    129 void VideoCaptureManager::UseFakeDevice() {
    130   use_fake_device_ = true;
    131 }
    132 
    133 void VideoCaptureManager::OnEnumerateDevices(MediaStreamType stream_type) {
    134   SCOPED_UMA_HISTOGRAM_TIMER(
    135       "Media.VideoCaptureManager.OnEnumerateDevicesTime");
    136   DCHECK(IsOnDeviceThread());
    137 
    138   media::VideoCaptureDevice::Names device_names;
    139   GetAvailableDevices(stream_type, &device_names);
    140 
    141   scoped_ptr<StreamDeviceInfoArray> devices(new StreamDeviceInfoArray());
    142   for (media::VideoCaptureDevice::Names::iterator it =
    143            device_names.begin(); it != device_names.end(); ++it) {
    144     bool opened = DeviceOpened(*it);
    145     devices->push_back(StreamDeviceInfo(
    146         stream_type, it->GetNameAndModel(), it->id(), opened));
    147   }
    148 
    149   PostOnDevicesEnumerated(stream_type, devices.Pass());
    150 }
    151 
    152 void VideoCaptureManager::OnOpen(int capture_session_id,
    153                                  const StreamDeviceInfo& device) {
    154   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.OnOpenTime");
    155   DCHECK(IsOnDeviceThread());
    156   DCHECK(devices_.find(capture_session_id) == devices_.end());
    157   DVLOG(1) << "VideoCaptureManager::OnOpen, id " << capture_session_id;
    158 
    159   // Check if another session has already opened this device. If so, just
    160   // use that opened device.
    161   media::VideoCaptureDevice* opened_video_capture_device =
    162       GetOpenedDevice(device);
    163   if (opened_video_capture_device) {
    164     DeviceEntry& new_entry = devices_[capture_session_id];
    165     new_entry.stream_type = device.device.type;
    166     new_entry.capture_device = opened_video_capture_device;
    167     PostOnOpened(device.device.type, capture_session_id);
    168     return;
    169   }
    170 
    171   scoped_ptr<media::VideoCaptureDevice> video_capture_device;
    172 
    173   // Open the device.
    174   switch (device.device.type) {
    175     case MEDIA_DEVICE_VIDEO_CAPTURE: {
    176       // We look up the device id from the renderer in our local enumeration
    177       // since the renderer does not have all the information that might be
    178       // held in the browser-side VideoCaptureDevice::Name structure.
    179       media::VideoCaptureDevice::Name* found =
    180           video_capture_devices_.FindById(device.device.id);
    181       if (found) {
    182         video_capture_device.reset(use_fake_device_ ?
    183             media::FakeVideoCaptureDevice::Create(*found) :
    184             media::VideoCaptureDevice::Create(*found));
    185       }
    186       break;
    187     }
    188     case MEDIA_TAB_VIDEO_CAPTURE: {
    189       video_capture_device.reset(
    190           WebContentsVideoCaptureDevice::Create(device.device.id));
    191       break;
    192     }
    193     case MEDIA_DESKTOP_VIDEO_CAPTURE: {
    194 #if defined(ENABLE_SCREEN_CAPTURE)
    195       DesktopMediaID id = DesktopMediaID::Parse(device.device.id);
    196       if (id.type != DesktopMediaID::TYPE_NONE) {
    197         video_capture_device = DesktopCaptureDevice::Create(id);
    198       }
    199 #endif  // defined(ENABLE_SCREEN_CAPTURE)
    200       break;
    201     }
    202     default: {
    203       NOTIMPLEMENTED();
    204       break;
    205     }
    206   }
    207 
    208   if (!video_capture_device) {
    209     PostOnError(capture_session_id, kDeviceNotAvailable);
    210     return;
    211   }
    212 
    213   DeviceEntry& new_entry = devices_[capture_session_id];
    214   new_entry.stream_type = device.device.type;
    215   new_entry.capture_device = video_capture_device.release();
    216   PostOnOpened(device.device.type, capture_session_id);
    217 }
    218 
    219 void VideoCaptureManager::OnClose(int capture_session_id) {
    220   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.OnCloseTime");
    221   DCHECK(IsOnDeviceThread());
    222   DVLOG(1) << "VideoCaptureManager::OnClose, id " << capture_session_id;
    223 
    224   VideoCaptureDevices::iterator device_it = devices_.find(capture_session_id);
    225   if (device_it == devices_.end()) {
    226     return;
    227   }
    228   const DeviceEntry removed_entry = device_it->second;
    229   devices_.erase(device_it);
    230 
    231   Controllers::iterator cit = controllers_.find(removed_entry.capture_device);
    232   if (cit != controllers_.end()) {
    233     BrowserThread::PostTask(
    234         BrowserThread::IO, FROM_HERE,
    235         base::Bind(&VideoCaptureController::StopSession,
    236                    cit->second->controller, capture_session_id));
    237   }
    238 
    239   if (!DeviceInUse(removed_entry.capture_device)) {
    240     // No other users of this device, deallocate (if not done already) and
    241     // delete the device. No need to take care of the controller, that is done
    242     // by |OnStop|.
    243     removed_entry.capture_device->DeAllocate();
    244     Controllers::iterator cit = controllers_.find(removed_entry.capture_device);
    245     if (cit != controllers_.end()) {
    246       delete cit->second;
    247       controllers_.erase(cit);
    248     }
    249     delete removed_entry.capture_device;
    250   }
    251 
    252   PostOnClosed(removed_entry.stream_type, capture_session_id);
    253 }
    254 
    255 void VideoCaptureManager::OnStart(
    256     const media::VideoCaptureParams capture_params,
    257     media::VideoCaptureDevice::EventHandler* video_capture_receiver) {
    258   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.OnStartTime");
    259   DCHECK(IsOnDeviceThread());
    260   DCHECK(video_capture_receiver != NULL);
    261   DVLOG(1) << "VideoCaptureManager::OnStart, (" << capture_params.width
    262            << ", " << capture_params.height
    263            << ", " << capture_params.frame_per_second
    264            << ", " << capture_params.session_id
    265            << ")";
    266 
    267   media::VideoCaptureDevice* video_capture_device =
    268       GetDeviceInternal(capture_params.session_id);
    269   if (!video_capture_device) {
    270     // Invalid session id.
    271     video_capture_receiver->OnError();
    272     return;
    273   }
    274   // TODO(mcasas): Variable resolution video capture devices, are not yet
    275   // fully supported, see crbug.com/261410, second part, and crbug.com/266082 .
    276   if (capture_params.frame_size_type !=
    277       media::ConstantResolutionVideoCaptureDevice) {
    278     LOG(DFATAL) << "Only constant Video Capture resolution device supported.";
    279     video_capture_receiver->OnError();
    280     return;
    281   }
    282   Controllers::iterator cit = controllers_.find(video_capture_device);
    283   if (cit != controllers_.end()) {
    284     cit->second->ready_to_delete = false;
    285   }
    286 
    287   // Possible errors are signaled to video_capture_receiver by
    288   // video_capture_device. video_capture_receiver to perform actions.
    289   media::VideoCaptureCapability params_as_capability_copy;
    290   params_as_capability_copy.width = capture_params.width;
    291   params_as_capability_copy.height = capture_params.height;
    292   params_as_capability_copy.frame_rate = capture_params.frame_per_second;
    293   params_as_capability_copy.session_id = capture_params.session_id;
    294   params_as_capability_copy.frame_size_type = capture_params.frame_size_type;
    295   video_capture_device->Allocate(params_as_capability_copy,
    296                                  video_capture_receiver);
    297   video_capture_device->Start();
    298 }
    299 
    300 void VideoCaptureManager::OnStop(
    301     const media::VideoCaptureSessionId capture_session_id,
    302     base::Closure stopped_cb) {
    303   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.OnStopTime");
    304   DCHECK(IsOnDeviceThread());
    305   DVLOG(1) << "VideoCaptureManager::OnStop, id " << capture_session_id;
    306 
    307   VideoCaptureDevices::iterator it = devices_.find(capture_session_id);
    308   if (it != devices_.end()) {
    309     media::VideoCaptureDevice* video_capture_device = it->second.capture_device;
    310     // Possible errors are signaled to video_capture_receiver by
    311     // video_capture_device. video_capture_receiver to perform actions.
    312     video_capture_device->Stop();
    313     video_capture_device->DeAllocate();
    314     Controllers::iterator cit = controllers_.find(video_capture_device);
    315     if (cit != controllers_.end()) {
    316       cit->second->ready_to_delete = true;
    317       if (cit->second->handlers.empty()) {
    318         delete cit->second;
    319         controllers_.erase(cit);
    320       }
    321     }
    322   }
    323 
    324   if (!stopped_cb.is_null())
    325     stopped_cb.Run();
    326 
    327   if (capture_session_id == kStartOpenSessionId) {
    328     // This device was opened from Start(), not Open(). Close it!
    329     OnClose(capture_session_id);
    330   }
    331 }
    332 
    333 void VideoCaptureManager::OnOpened(MediaStreamType stream_type,
    334                                    int capture_session_id) {
    335   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    336   if (!listener_) {
    337     // Listener has been removed.
    338     return;
    339   }
    340   listener_->Opened(stream_type, capture_session_id);
    341 }
    342 
    343 void VideoCaptureManager::OnClosed(MediaStreamType stream_type,
    344                                    int capture_session_id) {
    345   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    346   if (!listener_) {
    347     // Listener has been removed.
    348     return;
    349   }
    350   listener_->Closed(stream_type, capture_session_id);
    351 }
    352 
    353 void VideoCaptureManager::OnDevicesEnumerated(
    354     MediaStreamType stream_type,
    355     scoped_ptr<StreamDeviceInfoArray> devices) {
    356   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    357   if (!listener_) {
    358     // Listener has been removed.
    359     return;
    360   }
    361   listener_->DevicesEnumerated(stream_type, *devices);
    362 }
    363 
    364 void VideoCaptureManager::OnError(MediaStreamType stream_type,
    365                                   int capture_session_id,
    366                                   MediaStreamProviderError error) {
    367   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    368   if (!listener_) {
    369     // Listener has been removed.
    370     return;
    371   }
    372   listener_->Error(stream_type, capture_session_id, error);
    373 }
    374 
    375 void VideoCaptureManager::PostOnOpened(
    376     MediaStreamType stream_type, int capture_session_id) {
    377   DCHECK(IsOnDeviceThread());
    378   BrowserThread::PostTask(BrowserThread::IO,
    379                           FROM_HERE,
    380                           base::Bind(&VideoCaptureManager::OnOpened, this,
    381                                      stream_type, capture_session_id));
    382 }
    383 
    384 void VideoCaptureManager::PostOnClosed(
    385     MediaStreamType stream_type, int capture_session_id) {
    386   DCHECK(IsOnDeviceThread());
    387   BrowserThread::PostTask(BrowserThread::IO,
    388                           FROM_HERE,
    389                           base::Bind(&VideoCaptureManager::OnClosed, this,
    390                                      stream_type, capture_session_id));
    391 }
    392 
    393 void VideoCaptureManager::PostOnDevicesEnumerated(
    394     MediaStreamType stream_type,
    395     scoped_ptr<StreamDeviceInfoArray> devices) {
    396   DCHECK(IsOnDeviceThread());
    397   BrowserThread::PostTask(
    398       BrowserThread::IO, FROM_HERE,
    399       base::Bind(&VideoCaptureManager::OnDevicesEnumerated,
    400                  this, stream_type, base::Passed(&devices)));
    401 }
    402 
    403 void VideoCaptureManager::PostOnError(int capture_session_id,
    404                                       MediaStreamProviderError error) {
    405   DCHECK(IsOnDeviceThread());
    406   MediaStreamType stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
    407   VideoCaptureDevices::const_iterator it = devices_.find(capture_session_id);
    408   if (it != devices_.end())
    409     stream_type = it->second.stream_type;
    410   BrowserThread::PostTask(BrowserThread::IO,
    411                           FROM_HERE,
    412                           base::Bind(&VideoCaptureManager::OnError, this,
    413                                      stream_type, capture_session_id, error));
    414 }
    415 
    416 bool VideoCaptureManager::IsOnDeviceThread() const {
    417   return device_loop_->BelongsToCurrentThread();
    418 }
    419 
    420 void VideoCaptureManager::GetAvailableDevices(
    421     MediaStreamType stream_type,
    422     media::VideoCaptureDevice::Names* device_names) {
    423   DCHECK(IsOnDeviceThread());
    424 
    425   switch (stream_type) {
    426     case MEDIA_DEVICE_VIDEO_CAPTURE:
    427       // Cache the latest enumeration of video capture devices.
    428       // We'll refer to this list again in OnOpen to avoid having to
    429       // enumerate the devices again.
    430       video_capture_devices_.clear();
    431       if (!use_fake_device_) {
    432         media::VideoCaptureDevice::GetDeviceNames(&video_capture_devices_);
    433       } else {
    434         media::FakeVideoCaptureDevice::GetDeviceNames(&video_capture_devices_);
    435       }
    436       *device_names = video_capture_devices_;
    437       break;
    438 
    439     case MEDIA_DESKTOP_VIDEO_CAPTURE:
    440       device_names->clear();
    441       break;
    442 
    443     default:
    444       NOTREACHED();
    445       break;
    446   }
    447 }
    448 
    449 bool VideoCaptureManager::DeviceOpened(
    450     const media::VideoCaptureDevice::Name& device_name) {
    451   DCHECK(IsOnDeviceThread());
    452 
    453   for (VideoCaptureDevices::iterator it = devices_.begin();
    454        it != devices_.end(); ++it) {
    455     if (device_name.id() == it->second.capture_device->device_name().id()) {
    456       // We've found the device!
    457       return true;
    458     }
    459   }
    460   return false;
    461 }
    462 
    463 media::VideoCaptureDevice* VideoCaptureManager::GetOpenedDevice(
    464     const StreamDeviceInfo& device_info) {
    465   DCHECK(IsOnDeviceThread());
    466 
    467   for (VideoCaptureDevices::iterator it = devices_.begin();
    468        it != devices_.end(); it++) {
    469     if (device_info.device.id ==
    470             it->second.capture_device->device_name().id()) {
    471       return it->second.capture_device;
    472     }
    473   }
    474   return NULL;
    475 }
    476 
    477 bool VideoCaptureManager::DeviceInUse(
    478     const media::VideoCaptureDevice* video_capture_device) {
    479   DCHECK(IsOnDeviceThread());
    480 
    481   for (VideoCaptureDevices::iterator it = devices_.begin();
    482        it != devices_.end(); ++it) {
    483     if (video_capture_device == it->second.capture_device) {
    484       // We've found the device!
    485       return true;
    486     }
    487   }
    488   return false;
    489 }
    490 
    491 void VideoCaptureManager::AddController(
    492     const media::VideoCaptureParams& capture_params,
    493     VideoCaptureControllerEventHandler* handler,
    494     base::Callback<void(VideoCaptureController*)> added_cb) {
    495   DCHECK(handler);
    496   device_loop_->PostTask(
    497       FROM_HERE,
    498       base::Bind(&VideoCaptureManager::DoAddControllerOnDeviceThread,
    499                  this, capture_params, handler, added_cb));
    500 }
    501 
    502 void VideoCaptureManager::DoAddControllerOnDeviceThread(
    503     const media::VideoCaptureParams capture_params,
    504     VideoCaptureControllerEventHandler* handler,
    505     base::Callback<void(VideoCaptureController*)> added_cb) {
    506   DCHECK(IsOnDeviceThread());
    507 
    508   media::VideoCaptureDevice* video_capture_device =
    509       GetDeviceInternal(capture_params.session_id);
    510   scoped_refptr<VideoCaptureController> controller;
    511   if (video_capture_device) {
    512     Controllers::iterator cit = controllers_.find(video_capture_device);
    513     if (cit == controllers_.end()) {
    514       controller = new VideoCaptureController(this);
    515       controllers_[video_capture_device] =
    516           new Controller(controller.get(), handler);
    517     } else {
    518       controllers_[video_capture_device]->handlers.push_front(handler);
    519       controller = controllers_[video_capture_device]->controller;
    520     }
    521   }
    522   added_cb.Run(controller.get());
    523 }
    524 
    525 void VideoCaptureManager::RemoveController(
    526     VideoCaptureController* controller,
    527     VideoCaptureControllerEventHandler* handler) {
    528   DCHECK(handler);
    529   device_loop_->PostTask(
    530       FROM_HERE,
    531       base::Bind(&VideoCaptureManager::DoRemoveControllerOnDeviceThread, this,
    532                  make_scoped_refptr(controller), handler));
    533 }
    534 
    535 void VideoCaptureManager::DoRemoveControllerOnDeviceThread(
    536     VideoCaptureController* controller,
    537     VideoCaptureControllerEventHandler* handler) {
    538   DCHECK(IsOnDeviceThread());
    539 
    540   for (Controllers::iterator cit = controllers_.begin();
    541        cit != controllers_.end(); ++cit) {
    542     if (controller == cit->second->controller.get()) {
    543       Handlers& handlers = cit->second->handlers;
    544       for (Handlers::iterator hit = handlers.begin();
    545            hit != handlers.end(); ++hit) {
    546         if ((*hit) == handler) {
    547           handlers.erase(hit);
    548           break;
    549         }
    550       }
    551       if (handlers.empty() && cit->second->ready_to_delete) {
    552         delete cit->second;
    553         controllers_.erase(cit);
    554       }
    555       return;
    556     }
    557   }
    558 }
    559 
    560 media::VideoCaptureDevice* VideoCaptureManager::GetDeviceInternal(
    561     int capture_session_id) {
    562   DCHECK(IsOnDeviceThread());
    563   VideoCaptureDevices::iterator dit = devices_.find(capture_session_id);
    564   if (dit != devices_.end()) {
    565     return dit->second.capture_device;
    566   }
    567 
    568   // Solution for not using MediaStreamManager.
    569   // This session id won't be returned by Open().
    570   if (capture_session_id == kStartOpenSessionId) {
    571     media::VideoCaptureDevice::Names device_names;
    572     GetAvailableDevices(MEDIA_DEVICE_VIDEO_CAPTURE, &device_names);
    573     if (device_names.empty()) {
    574       // No devices available.
    575       return NULL;
    576     }
    577     StreamDeviceInfo device(MEDIA_DEVICE_VIDEO_CAPTURE,
    578                             device_names.front().GetNameAndModel(),
    579                             device_names.front().id(),
    580                             false);
    581 
    582     // Call OnOpen to open using the first device in the list.
    583     OnOpen(capture_session_id, device);
    584 
    585     VideoCaptureDevices::iterator dit = devices_.find(capture_session_id);
    586     if (dit != devices_.end()) {
    587       return dit->second.capture_device;
    588     }
    589   }
    590   return NULL;
    591 }
    592 
    593 }  // namespace content
    594