Home | History | Annotate | Download | only in webcam_private
      1 // Copyright 2014 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 "chrome/browser/extensions/api/webcam_private/webcam_private_api.h"
      6 
      7 #include <fcntl.h>
      8 #include <linux/videodev2.h>
      9 #include <stdio.h>
     10 #include <sys/ioctl.h>
     11 #include <unistd.h>
     12 
     13 #include "base/files/scoped_file.h"
     14 #include "base/posix/eintr_wrapper.h"
     15 #include "chrome/common/extensions/api/webcam_private.h"
     16 #include "content/public/browser/browser_context.h"
     17 #include "content/public/browser/media_device_id.h"
     18 #include "content/public/browser/resource_context.h"
     19 #include "content/public/common/media_stream_request.h"
     20 
     21 #define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32)
     22 #define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33)
     23 
     24 namespace content {
     25 class BrowserContext;
     26 }  // namespace content
     27 
     28 namespace {
     29 
     30 base::ScopedFD OpenWebcam(const std::string& extension_id,
     31                           content::BrowserContext* browser_context,
     32                           const std::string& webcam_id) {
     33   GURL security_origin =
     34       extensions::Extension::GetBaseURLFromExtensionId(extension_id);
     35 
     36   std::string device_id;
     37   bool success = content::GetMediaDeviceIDForHMAC(
     38       content::MEDIA_DEVICE_VIDEO_CAPTURE,
     39       browser_context->GetResourceContext()->GetMediaDeviceIDSalt(),
     40       security_origin,
     41       webcam_id,
     42       &device_id);
     43 
     44   if (!success)
     45     return base::ScopedFD();
     46 
     47   return base::ScopedFD(HANDLE_EINTR(open(device_id.c_str(), 0)));
     48 }
     49 
     50 void SetWebcamParameter(int fd, uint32_t control_id, int value) {
     51   struct v4l2_control v4l2_ctrl = {control_id, value};
     52   HANDLE_EINTR(ioctl(fd, VIDIOC_S_CTRL, &v4l2_ctrl));
     53 }
     54 
     55 bool GetWebcamParameter(int fd, uint32_t control_id, int* value) {
     56   struct v4l2_control v4l2_ctrl = {control_id};
     57 
     58   if (HANDLE_EINTR(ioctl(fd, VIDIOC_G_CTRL, &v4l2_ctrl)))
     59     return false;
     60 
     61   *value = v4l2_ctrl.value;
     62   return true;
     63 }
     64 
     65 const char kUnknownWebcam[] = "Unknown webcam id";
     66 }  // namespace
     67 
     68 namespace extensions {
     69 
     70 WebcamPrivateSetFunction::WebcamPrivateSetFunction() {
     71 }
     72 
     73 WebcamPrivateSetFunction::~WebcamPrivateSetFunction() {
     74 }
     75 
     76 bool WebcamPrivateSetFunction::RunSync() {
     77   // Get parameters
     78   scoped_ptr<api::webcam_private::Set::Params> params(
     79       api::webcam_private::Set::Params::Create(*args_));
     80   EXTENSION_FUNCTION_VALIDATE(params.get());
     81 
     82   base::ScopedFD fd =
     83       OpenWebcam(extension_id(), browser_context(), params->webcam_id);
     84   if (!fd.is_valid()) {
     85     SetError(kUnknownWebcam);
     86     return false;
     87   }
     88 
     89   if (params->config.pan) {
     90     SetWebcamParameter(fd.get(), V4L2_CID_PAN_ABSOLUTE,
     91                        *(params->config.pan));
     92   }
     93 
     94   if (params->config.pan_direction) {
     95     int direction = 0;
     96     switch (params->config.pan_direction) {
     97       case api::webcam_private::PAN_DIRECTION_NONE:
     98       case api::webcam_private::PAN_DIRECTION_STOP:
     99         direction = 0;
    100         break;
    101 
    102       case api::webcam_private::PAN_DIRECTION_RIGHT:
    103         direction = 1;
    104         break;
    105 
    106       case api::webcam_private::PAN_DIRECTION_LEFT:
    107         direction = -1;
    108         break;
    109     }
    110     SetWebcamParameter(fd.get(), V4L2_CID_PAN_SPEED, direction);
    111   }
    112 
    113   if (params->config.tilt) {
    114     SetWebcamParameter(fd.get(), V4L2_CID_TILT_ABSOLUTE,
    115                        *(params->config.tilt));
    116   }
    117 
    118   if (params->config.tilt_direction) {
    119     int direction = 0;
    120     switch (params->config.tilt_direction) {
    121       case api::webcam_private::TILT_DIRECTION_NONE:
    122       case api::webcam_private::TILT_DIRECTION_STOP:
    123         direction = 0;
    124         break;
    125 
    126       case api::webcam_private::TILT_DIRECTION_UP:
    127         direction = 1;
    128         break;
    129 
    130       case api::webcam_private::TILT_DIRECTION_DOWN:
    131         direction = -1;
    132         break;
    133     }
    134     SetWebcamParameter(fd.get(), V4L2_CID_TILT_SPEED, direction);
    135   }
    136 
    137   if (params->config.zoom) {
    138     SetWebcamParameter(fd.get(), V4L2_CID_ZOOM_ABSOLUTE,
    139                        *(params->config.zoom));
    140   }
    141 
    142 
    143   return true;
    144 }
    145 
    146 WebcamPrivateGetFunction::WebcamPrivateGetFunction() {
    147 }
    148 
    149 WebcamPrivateGetFunction::~WebcamPrivateGetFunction() {
    150 }
    151 
    152 bool WebcamPrivateGetFunction::RunSync() {
    153   // Get parameters
    154   scoped_ptr<api::webcam_private::Get::Params> params(
    155       api::webcam_private::Get::Params::Create(*args_));
    156   EXTENSION_FUNCTION_VALIDATE(params.get());
    157 
    158   base::ScopedFD fd =
    159       OpenWebcam(extension_id(), browser_context(), params->webcam_id);
    160   if (!fd.is_valid()) {
    161     SetError(kUnknownWebcam);
    162     return false;
    163   }
    164 
    165   api::webcam_private::WebcamConfiguration result;
    166 
    167   int pan;
    168   if (GetWebcamParameter(fd.get(), V4L2_CID_PAN_ABSOLUTE, &pan))
    169     result.pan.reset(new double(pan));
    170 
    171   int tilt;
    172   if (GetWebcamParameter(fd.get(), V4L2_CID_TILT_ABSOLUTE, &tilt))
    173     result.tilt.reset(new double(tilt));
    174 
    175   int zoom;
    176   if (GetWebcamParameter(fd.get(), V4L2_CID_ZOOM_ABSOLUTE, &zoom))
    177     result.zoom.reset(new double(zoom));
    178 
    179   SetResult(result.ToValue().release());
    180 
    181   return true;
    182 }
    183 
    184 WebcamPrivateResetFunction::WebcamPrivateResetFunction() {
    185 }
    186 
    187 WebcamPrivateResetFunction::~WebcamPrivateResetFunction() {
    188 }
    189 
    190 bool WebcamPrivateResetFunction::RunSync() {
    191   // Get parameters
    192   scoped_ptr<api::webcam_private::Reset::Params> params(
    193       api::webcam_private::Reset::Params::Create(*args_));
    194   EXTENSION_FUNCTION_VALIDATE(params.get());
    195 
    196   base::ScopedFD fd =
    197       OpenWebcam(extension_id(), browser_context(), params->webcam_id);
    198   if (!fd.is_valid()) {
    199     SetError(kUnknownWebcam);
    200     return false;
    201   }
    202 
    203   if (params->config.pan) {
    204     struct v4l2_control v4l2_ctrl = {V4L2_CID_PAN_RESET};
    205     HANDLE_EINTR(ioctl(fd.get(), VIDIOC_S_CTRL, &v4l2_ctrl));
    206   }
    207 
    208   if (params->config.tilt) {
    209     struct v4l2_control v4l2_ctrl = {V4L2_CID_TILT_RESET};
    210     HANDLE_EINTR(ioctl(fd.get(), VIDIOC_S_CTRL, &v4l2_ctrl));
    211   }
    212 
    213   if (params->config.zoom) {
    214     const int kDefaultZoom = 100;
    215     SetWebcamParameter(fd.get(), V4L2_CID_ZOOM_ABSOLUTE, kDefaultZoom);
    216   }
    217 
    218   return true;
    219 }
    220 
    221 }  // namespace extensions
    222