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.
5 #include "extensions/browser/api/webcam_private/webcam_private_api.h"
8 #include <linux/uvcvideo.h>
9 #include <linux/videodev2.h>
11 #include <sys/ioctl.h>
14 #include "base/files/scoped_file.h"
15 #include "base/posix/eintr_wrapper.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 #include "extensions/common/api/webcam_private.h"
22 #define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32)
23 #define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33)
24 #define V4L2_CID_PANTILT_CMD (V4L2_CID_CAMERA_CLASS_BASE+34)
26 // GUID of the Extension Unit for Logitech CC3300e motor control:
27 // {212de5ff-3080-2c4e-82d9-f587d00540bd}
28 #define UVC_GUID_LOGITECH_CC3000E_MOTORS \
29 {0x21, 0x2d, 0xe5, 0xff, 0x30, 0x80, 0x2c, 0x4e, \
30 0x82, 0xd9, 0xf5, 0x87, 0xd0, 0x05, 0x40, 0xbd}
32 #define LOGITECH_MOTORCONTROL_PANTILT_CMD 2
34 namespace webcam_private
= extensions::core_api::webcam_private
;
38 } // namespace content
41 const int kLogitechMenuIndexGoHome
= 2;
43 const uvc_menu_info kLogitechCmdMenu
[] = {
44 {1, "Set Preset"}, {2, "Get Preset"}, {3, "Go Home"}
47 const uvc_xu_control_mapping kLogitechCmdMapping
= {
50 UVC_GUID_LOGITECH_CC3000E_MOTORS
,
51 LOGITECH_MOTORCONTROL_PANTILT_CMD
,
55 UVC_CTRL_DATA_TYPE_ENUM
,
56 const_cast<uvc_menu_info
*>(&kLogitechCmdMenu
[0]),
57 arraysize(kLogitechCmdMenu
),
60 base::ScopedFD
OpenWebcam(const std::string
& extension_id
,
61 content::BrowserContext
* browser_context
,
62 const std::string
& webcam_id
) {
63 GURL security_origin
=
64 extensions::Extension::GetBaseURLFromExtensionId(extension_id
);
66 std::string device_id
;
67 bool success
= content::GetMediaDeviceIDForHMAC(
68 content::MEDIA_DEVICE_VIDEO_CAPTURE
,
69 browser_context
->GetResourceContext()->GetMediaDeviceIDSalt(),
75 return base::ScopedFD();
77 return base::ScopedFD(HANDLE_EINTR(open(device_id
.c_str(), 0)));
80 void SetWebcamParameter(int fd
, uint32_t control_id
, int value
) {
81 struct v4l2_control v4l2_ctrl
= {control_id
, value
};
82 HANDLE_EINTR(ioctl(fd
, VIDIOC_S_CTRL
, &v4l2_ctrl
));
85 bool GetWebcamParameter(int fd
, uint32_t control_id
, int* value
) {
86 struct v4l2_control v4l2_ctrl
= {control_id
};
88 if (HANDLE_EINTR(ioctl(fd
, VIDIOC_G_CTRL
, &v4l2_ctrl
)))
91 *value
= v4l2_ctrl
.value
;
95 bool EnsureLogitechCommandsMapped(int fd
) {
96 int res
= ioctl(fd
, UVCIOC_CTRL_MAP
, &kLogitechCmdMapping
);
97 // If mapping is successful or it's already mapped, this is a Logitech camera.
98 return res
>= 0 || errno
== EEXIST
;
101 const char kUnknownWebcam
[] = "Unknown webcam id";
104 namespace extensions
{
106 WebcamPrivateSetFunction::WebcamPrivateSetFunction() {
109 WebcamPrivateSetFunction::~WebcamPrivateSetFunction() {
112 bool WebcamPrivateSetFunction::RunSync() {
114 scoped_ptr
<webcam_private::Set::Params
> params(
115 webcam_private::Set::Params::Create(*args_
));
116 EXTENSION_FUNCTION_VALIDATE(params
.get());
119 OpenWebcam(extension_id(), browser_context(), params
->webcam_id
);
120 if (!fd
.is_valid()) {
121 SetError(kUnknownWebcam
);
125 if (params
->config
.pan
) {
126 SetWebcamParameter(fd
.get(), V4L2_CID_PAN_ABSOLUTE
,
127 *(params
->config
.pan
));
130 if (params
->config
.pan_direction
) {
132 switch (params
->config
.pan_direction
) {
133 case webcam_private::PAN_DIRECTION_NONE
:
134 case webcam_private::PAN_DIRECTION_STOP
:
138 case webcam_private::PAN_DIRECTION_RIGHT
:
142 case webcam_private::PAN_DIRECTION_LEFT
:
146 SetWebcamParameter(fd
.get(), V4L2_CID_PAN_SPEED
, direction
);
149 if (params
->config
.tilt
) {
150 SetWebcamParameter(fd
.get(), V4L2_CID_TILT_ABSOLUTE
,
151 *(params
->config
.tilt
));
154 if (params
->config
.tilt_direction
) {
156 switch (params
->config
.tilt_direction
) {
157 case webcam_private::TILT_DIRECTION_NONE
:
158 case webcam_private::TILT_DIRECTION_STOP
:
162 case webcam_private::TILT_DIRECTION_UP
:
166 case webcam_private::TILT_DIRECTION_DOWN
:
170 SetWebcamParameter(fd
.get(), V4L2_CID_TILT_SPEED
, direction
);
173 if (params
->config
.zoom
) {
174 SetWebcamParameter(fd
.get(), V4L2_CID_ZOOM_ABSOLUTE
,
175 *(params
->config
.zoom
));
182 WebcamPrivateGetFunction::WebcamPrivateGetFunction() {
185 WebcamPrivateGetFunction::~WebcamPrivateGetFunction() {
188 bool WebcamPrivateGetFunction::RunSync() {
190 scoped_ptr
<webcam_private::Get::Params
> params(
191 webcam_private::Get::Params::Create(*args_
));
192 EXTENSION_FUNCTION_VALIDATE(params
.get());
195 OpenWebcam(extension_id(), browser_context(), params
->webcam_id
);
196 if (!fd
.is_valid()) {
197 SetError(kUnknownWebcam
);
201 webcam_private::WebcamConfiguration result
;
204 if (GetWebcamParameter(fd
.get(), V4L2_CID_PAN_ABSOLUTE
, &pan
))
205 result
.pan
.reset(new double(pan
));
208 if (GetWebcamParameter(fd
.get(), V4L2_CID_TILT_ABSOLUTE
, &tilt
))
209 result
.tilt
.reset(new double(tilt
));
212 if (GetWebcamParameter(fd
.get(), V4L2_CID_ZOOM_ABSOLUTE
, &zoom
))
213 result
.zoom
.reset(new double(zoom
));
215 SetResult(result
.ToValue().release());
220 WebcamPrivateResetFunction::WebcamPrivateResetFunction() {
223 WebcamPrivateResetFunction::~WebcamPrivateResetFunction() {
226 bool WebcamPrivateResetFunction::RunSync() {
228 scoped_ptr
<webcam_private::Reset::Params
> params(
229 webcam_private::Reset::Params::Create(*args_
));
230 EXTENSION_FUNCTION_VALIDATE(params
.get());
233 OpenWebcam(extension_id(), browser_context(), params
->webcam_id
);
234 if (!fd
.is_valid()) {
235 SetError(kUnknownWebcam
);
239 if (params
->config
.pan
|| params
->config
.tilt
) {
240 if (EnsureLogitechCommandsMapped(fd
.get())) {
241 SetWebcamParameter(fd
.get(), V4L2_CID_PANTILT_CMD
,
242 kLogitechMenuIndexGoHome
);
246 if (params
->config
.pan
) {
247 struct v4l2_control v4l2_ctrl
= {V4L2_CID_PAN_RESET
};
248 HANDLE_EINTR(ioctl(fd
.get(), VIDIOC_S_CTRL
, &v4l2_ctrl
));
251 if (params
->config
.tilt
) {
252 struct v4l2_control v4l2_ctrl
= {V4L2_CID_TILT_RESET
};
253 HANDLE_EINTR(ioctl(fd
.get(), VIDIOC_S_CTRL
, &v4l2_ctrl
));
256 if (params
->config
.zoom
) {
257 const int kDefaultZoom
= 100;
258 SetWebcamParameter(fd
.get(), V4L2_CID_ZOOM_ABSOLUTE
, kDefaultZoom
);
264 } // namespace extensions