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