Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / media / video_capture_manager.cc
index a1fcad7..a547037 100644 (file)
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
+#include "base/task_runner_util.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
 #include "content/browser/renderer_host/media/web_contents_video_capture_device.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/desktop_media_id.h"
 #include "content/public/common/content_switches.h"
-#include "content/public/common/desktop_media_id.h"
 #include "content/public/common/media_stream_request.h"
+#include "media/base/media_switches.h"
 #include "media/base/scoped_histogram_timer.h"
 #include "media/video/capture/fake_video_capture_device.h"
+#include "media/video/capture/file_video_capture_device.h"
 #include "media/video/capture/video_capture_device.h"
 
 #if defined(ENABLE_SCREEN_CAPTURE)
 #include "content/browser/renderer_host/media/desktop_capture_device.h"
+#if defined(USE_AURA)
+#include "content/browser/renderer_host/media/desktop_capture_device_aura.h"
+#endif
 #endif
 
 namespace content {
@@ -39,23 +45,34 @@ VideoCaptureManager::DeviceEntry::DeviceEntry(
 
 VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
 
+VideoCaptureManager::DeviceInfo::DeviceInfo() {}
+
+VideoCaptureManager::DeviceInfo::DeviceInfo(
+    const media::VideoCaptureDevice::Name& name,
+    const media::VideoCaptureFormats& supported_formats)
+    : name(name),
+      supported_formats(supported_formats) {}
+
+VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
+
 VideoCaptureManager::VideoCaptureManager()
     : listener_(NULL),
       new_capture_session_id_(1),
-      use_fake_device_(false) {
+      artificial_device_source_for_testing_(DISABLED) {
 }
 
 VideoCaptureManager::~VideoCaptureManager() {
   DCHECK(devices_.empty());
 }
 
-void VideoCaptureManager::Register(MediaStreamProviderListener* listener,
-                                   base::MessageLoopProxy* device_thread_loop) {
+void VideoCaptureManager::Register(
+    MediaStreamProviderListener* listener,
+    const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   DCHECK(!listener_);
-  DCHECK(!device_loop_.get());
+  DCHECK(!device_task_runner_.get());
   listener_ = listener;
-  device_loop_ = device_thread_loop;
+  device_task_runner_ = device_task_runner;
 }
 
 void VideoCaptureManager::Unregister() {
@@ -68,10 +85,11 @@ void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
   DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type;
   DCHECK(listener_);
   base::PostTaskAndReplyWithResult(
-      device_loop_, FROM_HERE,
-      base::Bind(&VideoCaptureManager::GetAvailableDevicesOnDeviceThread, this,
-                 stream_type),
-      base::Bind(&VideoCaptureManager::OnDevicesEnumerated, this, stream_type));
+      device_task_runner_, FROM_HERE,
+      base::Bind(&VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread,
+                 this, stream_type, devices_info_cache_),
+      base::Bind(&VideoCaptureManager::OnDevicesInfoEnumerated, this,
+                 stream_type));
 }
 
 int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
@@ -79,7 +97,8 @@ int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
   DCHECK(listener_);
 
   // Generate a new id for the session being opened.
-  const int capture_session_id = new_capture_session_id_++;
+  const media::VideoCaptureSessionId capture_session_id =
+      new_capture_session_id_++;
 
   DCHECK(sessions_.find(capture_session_id) == sessions_.end());
   DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id;
@@ -101,8 +120,8 @@ void VideoCaptureManager::Close(int capture_session_id) {
   DCHECK(listener_);
   DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
 
-  std::map<int, MediaStreamDevice>::iterator session_it =
-      sessions_.find(capture_session_id);
+  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator
+      session_it = sessions_.find(capture_session_id);
   if (session_it == sessions_.end()) {
     NOTREACHED();
     return;
@@ -128,12 +147,17 @@ void VideoCaptureManager::Close(int capture_session_id) {
 }
 
 void VideoCaptureManager::UseFakeDevice() {
-  use_fake_device_ = true;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseFileForFakeVideoCapture)) {
+    artificial_device_source_for_testing_ = Y4M_FILE;
+  } else {
+    artificial_device_source_for_testing_ = TEST_PATTERN;
+  }
 }
 
 void VideoCaptureManager::DoStartDeviceOnDeviceThread(
     DeviceEntry* entry,
-    const media::VideoCaptureCapability& capture_params,
+    const media::VideoCaptureParams& params,
     scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
   DCHECK(IsOnDeviceThread());
@@ -144,12 +168,22 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
       // We look up the device id from the renderer in our local enumeration
       // since the renderer does not have all the information that might be
       // held in the browser-side VideoCaptureDevice::Name structure.
-      media::VideoCaptureDevice::Name* found =
-          video_capture_devices_.FindById(entry->id);
+      DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_);
       if (found) {
-        video_capture_device.reset(use_fake_device_ ?
-            media::FakeVideoCaptureDevice::Create(*found) :
-            media::VideoCaptureDevice::Create(*found));
+        switch (artificial_device_source_for_testing_) {
+          case DISABLED:
+            video_capture_device.reset(
+                media::VideoCaptureDevice::Create(found->name));
+            break;
+          case TEST_PATTERN:
+            video_capture_device.reset(
+                media::FakeVideoCaptureDevice::Create(found->name));
+            break;
+          case Y4M_FILE:
+            video_capture_device.reset(
+                media::FileVideoCaptureDevice::Create(found->name));
+            break;
+        }
       }
       break;
     }
@@ -161,7 +195,13 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
     case MEDIA_DESKTOP_VIDEO_CAPTURE: {
 #if defined(ENABLE_SCREEN_CAPTURE)
       DesktopMediaID id = DesktopMediaID::Parse(entry->id);
-      if (id.type != DesktopMediaID::TYPE_NONE) {
+#if defined(USE_AURA)
+      if (id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
+        video_capture_device.reset(DesktopCaptureDeviceAura::Create(id));
+      } else
+#endif
+      if (id.type != DesktopMediaID::TYPE_NONE &&
+          id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
         video_capture_device = DesktopCaptureDevice::Create(id);
       }
 #endif  // defined(ENABLE_SCREEN_CAPTURE)
@@ -174,29 +214,27 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
   }
 
   if (!video_capture_device) {
-    device_client->OnError();
+    device_client->OnError("Could not create capture device");
     return;
   }
 
-  video_capture_device->AllocateAndStart(capture_params, device_client.Pass());
+  video_capture_device->AllocateAndStart(params, device_client.Pass());
   entry->video_capture_device = video_capture_device.Pass();
 }
 
 void VideoCaptureManager::StartCaptureForClient(
+    media::VideoCaptureSessionId session_id,
     const media::VideoCaptureParams& params,
     base::ProcessHandle client_render_process,
     VideoCaptureControllerID client_id,
     VideoCaptureControllerEventHandler* client_handler,
     const DoneCB& done_cb) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, ("
-         << params.requested_format.width
-         << ", " << params.requested_format.height
-         << ", " << params.requested_format.frame_rate
-         << ", #" << params.session_id
-         << ")";
-
-  DeviceEntry* entry = GetOrCreateDeviceEntry(params.session_id);
+  DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, "
+           << params.requested_format.frame_size.ToString() << ", "
+           << params.requested_format.frame_rate << ", #" << session_id << ")";
+
+  DeviceEntry* entry = GetOrCreateDeviceEntry(session_id);
   if (!entry) {
     done_cb.Run(base::WeakPtr<VideoCaptureController>());
     return;
@@ -209,24 +247,19 @@ void VideoCaptureManager::StartCaptureForClient(
     DVLOG(1) << "VideoCaptureManager starting device (type = "
              << entry->stream_type << ", id = " << entry->id << ")";
 
-    media::VideoCaptureCapability params_as_capability;
-    params_as_capability.width = params.requested_format.width;
-    params_as_capability.height = params.requested_format.height;
-    params_as_capability.frame_rate = params.requested_format.frame_rate;
-    params_as_capability.frame_size_type =
-        params.requested_format.frame_size_type;
-
-    device_loop_->PostTask(FROM_HERE, base::Bind(
-        &VideoCaptureManager::DoStartDeviceOnDeviceThread, this,
-        entry, params_as_capability,
-        base::Passed(entry->video_capture_controller->NewDeviceClient())));
+    device_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &VideoCaptureManager::DoStartDeviceOnDeviceThread,
+            this,
+            entry,
+            params,
+            base::Passed(entry->video_capture_controller->NewDeviceClient())));
   }
   // Run the callback first, as AddClient() may trigger OnFrameInfo().
   done_cb.Run(entry->video_capture_controller->GetWeakPtr());
-  entry->video_capture_controller->AddClient(client_id,
-                                             client_handler,
-                                             client_render_process,
-                                             params);
+  entry->video_capture_controller->AddClient(
+      client_id, client_handler, client_render_process, session_id, params);
 }
 
 void VideoCaptureManager::StopCaptureForClient(
@@ -244,7 +277,8 @@ void VideoCaptureManager::StopCaptureForClient(
   }
 
   // Detach client from controller.
-  int session_id = controller->RemoveClient(client_id, client_handler);
+  media::VideoCaptureSessionId session_id =
+      controller->RemoveClient(client_id, client_handler);
   DVLOG(1) << "VideoCaptureManager::StopCaptureForClient, session_id = "
            << session_id;
 
@@ -252,6 +286,49 @@ void VideoCaptureManager::StopCaptureForClient(
   DestroyDeviceEntryIfNoClients(entry);
 }
 
+bool VideoCaptureManager::GetDeviceSupportedFormats(
+    media::VideoCaptureSessionId capture_session_id,
+    media::VideoCaptureFormats* supported_formats) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK(supported_formats->empty());
+
+  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator it =
+      sessions_.find(capture_session_id);
+  if (it == sessions_.end())
+    return false;
+  DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
+
+  // Return all available formats of the device, regardless its started state.
+  DeviceInfo* existing_device =
+      FindDeviceInfoById(it->second.id, devices_info_cache_);
+  if (existing_device)
+    *supported_formats = existing_device->supported_formats;
+  return true;
+}
+
+bool VideoCaptureManager::GetDeviceFormatsInUse(
+    media::VideoCaptureSessionId capture_session_id,
+    media::VideoCaptureFormats* formats_in_use) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK(formats_in_use->empty());
+
+  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator it =
+      sessions_.find(capture_session_id);
+  if (it == sessions_.end())
+    return false;
+  DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name;
+
+  // Return the currently in-use format(s) of the device, if it's started.
+  DeviceEntry* device_in_use =
+      GetDeviceEntryForMediaStreamDevice(it->second);
+  if (device_in_use) {
+    // Currently only one format-in-use is supported at the VCC level.
+    formats_in_use->push_back(
+        device_in_use->video_capture_controller->GetVideoCaptureFormat());
+  }
+  return true;
+}
+
 void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
   DCHECK(IsOnDeviceThread());
@@ -261,8 +338,9 @@ void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
   entry->video_capture_device.reset();
 }
 
-void VideoCaptureManager::OnOpened(MediaStreamType stream_type,
-                                   int capture_session_id) {
+void VideoCaptureManager::OnOpened(
+    MediaStreamType stream_type,
+    media::VideoCaptureSessionId capture_session_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   if (!listener_) {
     // Listener has been removed.
@@ -271,8 +349,9 @@ void VideoCaptureManager::OnOpened(MediaStreamType stream_type,
   listener_->Opened(stream_type, capture_session_id);
 }
 
-void VideoCaptureManager::OnClosed(MediaStreamType stream_type,
-                                   int capture_session_id) {
+void VideoCaptureManager::OnClosed(
+    MediaStreamType stream_type,
+    media::VideoCaptureSessionId capture_session_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   if (!listener_) {
     // Listener has been removed.
@@ -281,54 +360,56 @@ void VideoCaptureManager::OnClosed(MediaStreamType stream_type,
   listener_->Closed(stream_type, capture_session_id);
 }
 
-void VideoCaptureManager::OnDevicesEnumerated(
+void VideoCaptureManager::OnDevicesInfoEnumerated(
     MediaStreamType stream_type,
-    const media::VideoCaptureDevice::Names& device_names) {
+    const DeviceInfos& new_devices_info_cache) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   if (!listener_) {
     // Listener has been removed.
     return;
   }
+  devices_info_cache_ = new_devices_info_cache;
 
-  // Transform from VCD::Name to StreamDeviceInfo.
+  // Walk the |devices_info_cache_| and transform from VCD::Name to
+  // StreamDeviceInfo for return purposes.
   StreamDeviceInfoArray devices;
-  for (media::VideoCaptureDevice::Names::const_iterator it =
-           device_names.begin(); it != device_names.end(); ++it) {
+  for (DeviceInfos::const_iterator it = devices_info_cache_.begin();
+       it != devices_info_cache_.end(); ++it) {
     devices.push_back(StreamDeviceInfo(
-        stream_type, it->GetNameAndModel(), it->id()));
+        stream_type, it->name.GetNameAndModel(), it->name.id()));
   }
-
   listener_->DevicesEnumerated(stream_type, devices);
 }
 
 bool VideoCaptureManager::IsOnDeviceThread() const {
-  return device_loop_->BelongsToCurrentThread();
+  return device_task_runner_->BelongsToCurrentThread();
 }
 
-media::VideoCaptureDevice::Names
-VideoCaptureManager::GetAvailableDevicesOnDeviceThread(
-    MediaStreamType stream_type) {
+VideoCaptureManager::DeviceInfos
+VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
+    MediaStreamType stream_type,
+    const DeviceInfos& old_device_info_cache) {
   SCOPED_UMA_HISTOGRAM_TIMER(
-      "Media.VideoCaptureManager.GetAvailableDevicesTime");
+      "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime");
   DCHECK(IsOnDeviceThread());
-  media::VideoCaptureDevice::Names result;
-
+  media::VideoCaptureDevice::Names names_snapshot;
   switch (stream_type) {
     case MEDIA_DEVICE_VIDEO_CAPTURE:
       // Cache the latest enumeration of video capture devices.
       // We'll refer to this list again in OnOpen to avoid having to
       // enumerate the devices again.
-      if (!use_fake_device_) {
-        media::VideoCaptureDevice::GetDeviceNames(&result);
-      } else {
-        media::FakeVideoCaptureDevice::GetDeviceNames(&result);
+      switch (artificial_device_source_for_testing_) {
+        case DISABLED:
+          media::VideoCaptureDevice::GetDeviceNames(&names_snapshot);
+          break;
+        case TEST_PATTERN:
+          media::FakeVideoCaptureDevice::GetDeviceNames(&names_snapshot);
+          break;
+        case Y4M_FILE:
+          media::FileVideoCaptureDevice::GetDeviceNames(&names_snapshot);
+          break;
       }
-
-      // TODO(nick): The correctness of device start depends on this cache being
-      // maintained, but it seems a little odd to keep a cache here. Can we
-      // eliminate it?
-      video_capture_devices_ = result;
       break;
 
     case MEDIA_DESKTOP_VIDEO_CAPTURE:
@@ -339,7 +420,48 @@ VideoCaptureManager::GetAvailableDevicesOnDeviceThread(
       NOTREACHED();
       break;
   }
-  return result;
+
+  // Construct |new_devices_info_cache| with the cached devices that are still
+  // present in the system, and remove their names from |names_snapshot|, so we
+  // keep there the truly new devices.
+  DeviceInfos new_devices_info_cache;
+  for (DeviceInfos::const_iterator it_device_info =
+           old_device_info_cache.begin();
+       it_device_info != old_device_info_cache.end(); ++it_device_info) {
+     for (media::VideoCaptureDevice::Names::iterator it =
+              names_snapshot.begin();
+          it != names_snapshot.end(); ++it) {
+      if (it_device_info->name.id() == it->id()) {
+        new_devices_info_cache.push_back(*it_device_info);
+        names_snapshot.erase(it);
+        break;
+      }
+    }
+  }
+
+  // Get the supported capture formats for the new devices in |names_snapshot|.
+  for (media::VideoCaptureDevice::Names::const_iterator it =
+           names_snapshot.begin();
+       it != names_snapshot.end(); ++it) {
+    media::VideoCaptureFormats supported_formats;
+    DeviceInfo device_info(*it, media::VideoCaptureFormats());
+    switch (artificial_device_source_for_testing_) {
+      case DISABLED:
+        media::VideoCaptureDevice::GetDeviceSupportedFormats(
+            *it, &(device_info.supported_formats));
+        break;
+      case TEST_PATTERN:
+        media::FakeVideoCaptureDevice::GetDeviceSupportedFormats(
+            *it, &(device_info.supported_formats));
+        break;
+      case Y4M_FILE:
+        media::FileVideoCaptureDevice::GetDeviceSupportedFormats(
+            *it, &(device_info.supported_formats));
+        break;
+    }
+    new_devices_info_cache.push_back(device_info);
+  }
+  return new_devices_info_cache;
 }
 
 VideoCaptureManager::DeviceEntry*
@@ -384,7 +506,7 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
     // DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
     devices_.erase(entry);
     entry->video_capture_controller.reset();
-    device_loop_->PostTask(
+    device_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
                    base::Owned(entry)));
@@ -392,11 +514,11 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
 }
 
 VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
-    int capture_session_id) {
+    media::VideoCaptureSessionId capture_session_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
-  std::map<int, MediaStreamDevice>::iterator session_it =
-      sessions_.find(capture_session_id);
+  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator
+      session_it = sessions_.find(capture_session_id);
   if (session_it == sessions_.end()) {
     return NULL;
   }
@@ -405,7 +527,7 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
   // Check if another session has already opened this device. If so, just
   // use that opened device.
   DeviceEntry* const existing_device =
-       GetDeviceEntryForMediaStreamDevice(device_info);
+      GetDeviceEntryForMediaStreamDevice(device_info);
   if (existing_device) {
     DCHECK_EQ(device_info.type, existing_device->stream_type);
     return existing_device;
@@ -420,4 +542,15 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
   return new_device;
 }
 
+VideoCaptureManager::DeviceInfo* VideoCaptureManager::FindDeviceInfoById(
+    const std::string& id,
+    DeviceInfos& device_vector) {
+  for (DeviceInfos::iterator it = device_vector.begin();
+       it != device_vector.end(); ++it) {
+    if (it->name.id() == id)
+      return &(*it);
+  }
+  return NULL;
+}
+
 }  // namespace content