cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / extensions / browser / api / webcam_private / visca_webcam.cc
blobbcc6b95cde9b77d8a6d89cd15bb0291065099c78
1 // Copyright 2015 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/visca_webcam.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/public/browser/browser_thread.h"
11 using content::BrowserThread;
13 namespace {
15 // Message terminator:
16 const char VISCA_TERMINATOR = 0xFF;
18 // Response types:
19 const char VISCA_RESPONSE_NETWORK_CHANGE = 0x38;
20 const char VISCA_RESPONSE_ACK = 0x40;
21 const char VISCA_RESPONSE_ERROR = 0x60;
23 // The default pan speed is MAX_PAN_SPEED /2 and the default tilt speed is
24 // MAX_TILT_SPEED / 2.
25 const int MAX_PAN_SPEED = 0x18;
26 const int MAX_TILT_SPEED = 0x14;
28 // Pan-Tilt-Zoom movement comands from http://www.manualslib.com/manual/...
29 // 557364/Cisco-Precisionhd-1080p12x.html?page=31#manual
31 // Reset the address of each device in the VISCA chain (broadcast). This is used
32 // when resetting the VISCA network.
33 const std::vector<char> kSetAddressCommand = {0x88, 0x30, 0x01, 0xFF};
35 // Clear all of the devices, halting any pending commands in the VISCA chain
36 // (broadcast). This is used when resetting the VISCA network.
37 const std::vector<char> kClearAllCommand = {0x88, 0x01, 0x00, 0x01, 0xFF};
39 // Clear the command buffer in the target device and cancel the command
40 // currently being executed. Command: {0x8X, 0x01, 0x00, 0x01, 0xFF}, X = 1 to
41 // 7: target device address.
42 const std::vector<char> kClearCommand = {0x81, 0x01, 0x00, 0x01, 0xFF};
44 // Command: {0x8X, 0x09, 0x06, 0x12, 0xFF}, X = 1 to 7: target device address.
45 // Response: {0xY0, 0x50, 0x0p, 0x0q, 0x0r, 0x0s, 0x0t, 0x0u, 0x0v, 0x0w, 0xFF},
46 // Y = socket number; pqrs: pan position; tuvw: tilt position.
47 const std::vector<char> kGetPanTiltCommand = {0x81, 0x09, 0x06, 0x12, 0xFF};
49 // Command: {0x8X, 0x01, 0x06, 0x02, 0x0p, 0x0t, 0x0q, 0x0r, 0x0s, 0x0u, 0x0v,
50 // 0x0w, 0x0y, 0x0z, 0xFF}, X = 1 to 7: target device address; p = pan speed;
51 // t = tilt speed; qrsu = pan position; vwyz = tilt position.
52 const std::vector<char> kSetPanTiltCommand = {0x81, 0x01, 0x06, 0x02, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00, 0xFF};
56 // Command: {0x8X, 0x01, 0x06, 0x05, 0xFF}, X = 1 to 7: target device address.
57 const std::vector<char> kResetPanTiltCommand = {0x81, 0x01, 0x06, 0x05, 0xFF};
59 // Command: {0x8X, 0x09, 0x04, 0x47, 0xFF}, X = 1 to 7: target device address.
60 // Response: {0xY0, 0x50, 0x0p, 0x0q, 0x0r, 0x0s, 0xFF}, Y = socket number;
61 // pqrs: zoom position.
62 const std::vector<char> kGetZoomCommand = {0x81, 0x09, 0x04, 0x47, 0xFF};
64 // Command: {0x8X, 0x01, 0x04, 0x47, 0x0p, 0x0q, 0x0r, 0x0s, 0xFF}, X = 1 to 7:
65 // target device address; pqrs: zoom position;
66 const std::vector<char> kSetZoomCommand =
67 {0x81, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF};
69 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x03, 0x01, 0xFF}, X = 1 to 7:
70 // target device address; p: pan speed; t: tilt speed.
71 const std::vector<char> kPTUpCommand = {0x81, 0x01, 0x06, 0x01, 0x00,
72 0x00, 0x03, 0x01, 0xFF};
74 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x03, 0x02, 0xFF}, X = 1 to 7:
75 // target device address; p: pan speed; t: tilt speed.
76 const std::vector<char> kPTDownCommand = {0x81, 0x01, 0x06, 0x01, 0x00,
77 0x00, 0x03, 0x02, 0xFF};
79 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x0, 0x03, 0xFF}, X = 1 to 7:
80 // target device address; p: pan speed; t: tilt speed.
81 const std::vector<char> kPTLeftCommand = {0x81, 0x01, 0x06, 0x01, 0x00,
82 0x00, 0x01, 0x03, 0xFF};
84 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x02, 0x03, 0xFF}, X = 1 to 7:
85 // target device address; p: pan speed; t: tilt speed.
86 const std::vector<char> kPTRightCommand = {0x81, 0x01, 0x06, 0x01, 0x00,
87 0x00, 0x02, 0x03, 0xFF};
89 // Command: {0x8X, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x03, 0xFF}, X = 1 to 7:
90 // target device address.
91 const std::vector<char> kPTStopCommand =
92 {0x81, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x03, 0xFF};
94 } // namespace
96 namespace extensions {
98 ViscaWebcam::ViscaWebcam(const std::string& path,
99 const std::string& extension_id)
100 : path_(path),
101 extension_id_(extension_id),
102 pan_(0),
103 tilt_(0),
104 weak_ptr_factory_(this) {}
106 ViscaWebcam::~ViscaWebcam() {
109 void ViscaWebcam::Open(const OpenCompleteCallback& open_callback) {
110 BrowserThread::PostTask(
111 BrowserThread::IO, FROM_HERE,
112 base::Bind(&ViscaWebcam::OpenOnIOThread, weak_ptr_factory_.GetWeakPtr(),
113 open_callback));
116 void ViscaWebcam::OpenOnIOThread(const OpenCompleteCallback& open_callback) {
117 DCHECK_CURRENTLY_ON(BrowserThread::IO);
119 api::serial::ConnectionOptions options;
121 // Set the receive buffer size to receive the response data 1 by 1.
122 options.buffer_size.reset(new int(1));
123 options.persistent.reset(new bool(false));
124 options.bitrate.reset(new int(9600));
125 options.cts_flow_control.reset(new bool(false));
126 options.receive_timeout.reset(new int(0));
127 options.send_timeout.reset(new int(0));
128 options.data_bits = api::serial::DATA_BITS_EIGHT;
129 options.parity_bit = api::serial::PARITY_BIT_NO;
130 options.stop_bits = api::serial::STOP_BITS_ONE;
132 serial_connection_.reset(new SerialConnection(path_, extension_id_));
133 serial_connection_->Open(
134 options, base::Bind(&ViscaWebcam::OnConnected,
135 weak_ptr_factory_.GetWeakPtr(), open_callback));
138 void ViscaWebcam::OnConnected(const OpenCompleteCallback& open_callback,
139 bool success) {
140 if (!success) {
141 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
142 base::Bind(open_callback, false));
143 } else {
144 Send(kSetAddressCommand,
145 base::Bind(&ViscaWebcam::OnAddressSetCompleted,
146 weak_ptr_factory_.GetWeakPtr(), open_callback));
150 void ViscaWebcam::OnAddressSetCompleted(
151 const OpenCompleteCallback& open_callback,
152 bool success,
153 const std::vector<char>& response) {
154 commands_.pop_front();
155 if (!success) {
156 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
157 base::Bind(open_callback, false));
158 } else {
159 Send(kClearAllCommand,
160 base::Bind(&ViscaWebcam::OnClearAllCompleted,
161 weak_ptr_factory_.GetWeakPtr(), open_callback));
165 void ViscaWebcam::OnClearAllCompleted(const OpenCompleteCallback& open_callback,
166 bool success,
167 const std::vector<char>& response) {
168 commands_.pop_front();
169 if (!success) {
170 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
171 base::Bind(open_callback, false));
172 } else {
173 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
174 base::Bind(open_callback, true));
178 void ViscaWebcam::Send(const std::vector<char>& command,
179 const CommandCompleteCallback& callback) {
180 commands_.push_back(std::make_pair(command, callback));
181 // If this is the only command in the queue, send it now.
182 if (commands_.size() == 1) {
183 serial_connection_->Send(
184 command, base::Bind(&ViscaWebcam::OnSendCompleted,
185 weak_ptr_factory_.GetWeakPtr(), callback));
189 void ViscaWebcam::OnSendCompleted(const CommandCompleteCallback& callback,
190 int bytes_sent,
191 api::serial::SendError error) {
192 if (error == api::serial::SEND_ERROR_NONE) {
193 ReceiveLoop(callback);
194 } else {
195 const std::vector<char> response;
196 callback.Run(false, response);
200 void ViscaWebcam::ReceiveLoop(const CommandCompleteCallback& callback) {
201 serial_connection_->Receive(base::Bind(&ViscaWebcam::OnReceiveCompleted,
202 weak_ptr_factory_.GetWeakPtr(),
203 callback));
206 void ViscaWebcam::OnReceiveCompleted(const CommandCompleteCallback& callback,
207 const std::vector<char>& data,
208 api::serial::ReceiveError error) {
209 data_buffer_.insert(data_buffer_.end(), data.begin(), data.end());
211 if (error == api::serial::RECEIVE_ERROR_NONE) {
212 // Loop until encounter the terminator.
213 if (int(data_buffer_.back()) != VISCA_TERMINATOR) {
214 base::MessageLoop::current()->PostTask(
215 FROM_HERE, base::Bind(&ViscaWebcam::ReceiveLoop,
216 weak_ptr_factory_.GetWeakPtr(), callback));
217 } else {
218 // Clear |data_buffer_|.
219 std::vector<char> response;
220 response.swap(data_buffer_);
222 if ((int(response[1]) & 0xF0) == VISCA_RESPONSE_ERROR) {
223 callback.Run(false, response);
224 } else if ((int(response[1]) & 0xF0) != VISCA_RESPONSE_ACK &&
225 (int(response[1]) & 0xFF) != VISCA_RESPONSE_NETWORK_CHANGE) {
226 callback.Run(true, response);
227 } else {
228 base::MessageLoop::current()->PostTask(
229 FROM_HERE, base::Bind(&ViscaWebcam::ReceiveLoop,
230 weak_ptr_factory_.GetWeakPtr(), callback));
233 } else {
234 // Clear |data_buffer_|.
235 std::vector<char> response;
236 response.swap(data_buffer_);
237 callback.Run(false, response);
241 void ViscaWebcam::OnCommandCompleted(const SetPTZCompleteCallback& callback,
242 bool success,
243 const std::vector<char>& response) {
244 // TODO(xdai): Error handling according to |response|.
245 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
246 base::Bind(callback, success));
247 commands_.pop_front();
249 // If there are pending commands, process the next one.
250 if (!commands_.empty()) {
251 const std::vector<char> next_command = commands_.front().first;
252 const CommandCompleteCallback next_callback = commands_.front().second;
253 serial_connection_->Send(
254 next_command,
255 base::Bind(&ViscaWebcam::OnSendCompleted,
256 weak_ptr_factory_.GetWeakPtr(), next_callback));
260 void ViscaWebcam::OnInquiryCompleted(InquiryType type,
261 const GetPTZCompleteCallback& callback,
262 bool success,
263 const std::vector<char>& response) {
264 int value = 0;
265 if (!success) {
266 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
267 base::Bind(callback, false, value));
268 } else {
269 switch (type) {
270 case INQUIRY_PAN:
271 // See kGetPanTiltCommand for the format of response.
272 pan_ = ((int(response[2]) & 0x0F) << 12) +
273 ((int(response[3]) & 0x0F) << 8) +
274 ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
275 value = pan_;
276 break;
277 case INQUIRY_TILT:
278 // See kGetPanTiltCommand for the format of response.
279 tilt_ = ((int(response[6]) & 0x0F) << 12) +
280 ((int(response[7]) & 0x0F) << 8) +
281 ((int(response[8]) & 0x0F) << 4) + (int(response[9]) & 0x0F);
282 value = tilt_;
283 break;
284 case INQUIRY_ZOOM:
285 // See kGetZoomCommand for the format of response.
286 value = ((int(response[2]) & 0x0F) << 12) +
287 ((int(response[3]) & 0x0F) << 8) +
288 ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
289 break;
291 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
292 base::Bind(callback, true, value));
294 commands_.pop_front();
296 // If there are pending commands, process the next one.
297 if (!commands_.empty()) {
298 const std::vector<char> next_command = commands_.front().first;
299 const CommandCompleteCallback next_callback = commands_.front().second;
300 serial_connection_->Send(
301 next_command,
302 base::Bind(&ViscaWebcam::OnSendCompleted,
303 weak_ptr_factory_.GetWeakPtr(), next_callback));
307 void ViscaWebcam::GetPan(const GetPTZCompleteCallback& callback) {
308 Send(kGetPanTiltCommand,
309 base::Bind(&ViscaWebcam::OnInquiryCompleted,
310 weak_ptr_factory_.GetWeakPtr(), INQUIRY_PAN, callback));
313 void ViscaWebcam::GetTilt(const GetPTZCompleteCallback& callback) {
314 Send(kGetPanTiltCommand,
315 base::Bind(&ViscaWebcam::OnInquiryCompleted,
316 weak_ptr_factory_.GetWeakPtr(), INQUIRY_TILT, callback));
319 void ViscaWebcam::GetZoom(const GetPTZCompleteCallback& callback) {
320 Send(kGetZoomCommand,
321 base::Bind(&ViscaWebcam::OnInquiryCompleted,
322 weak_ptr_factory_.GetWeakPtr(), INQUIRY_ZOOM, callback));
325 void ViscaWebcam::SetPan(int value,
326 int pan_speed,
327 const SetPTZCompleteCallback& callback) {
328 pan_speed = std::min(pan_speed, MAX_PAN_SPEED);
329 pan_speed = pan_speed > 0 ? pan_speed : MAX_PAN_SPEED / 2;
330 pan_ = value;
331 std::vector<char> command = kSetPanTiltCommand;
332 command[4] |= pan_speed;
333 command[5] |= (MAX_TILT_SPEED / 2);
334 command[6] |= ((pan_ & 0xF000) >> 12);
335 command[7] |= ((pan_ & 0x0F00) >> 8);
336 command[8] |= ((pan_ & 0x00F0) >> 4);
337 command[9] |= (pan_ & 0x000F);
338 command[10] |= ((tilt_ & 0xF000) >> 12);
339 command[11] |= ((tilt_ & 0x0F00) >> 8);
340 command[12] |= ((tilt_ & 0x00F0) >> 4);
341 command[13] |= (tilt_ & 0x000F);
342 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
343 weak_ptr_factory_.GetWeakPtr(), callback));
346 void ViscaWebcam::SetTilt(int value,
347 int tilt_speed,
348 const SetPTZCompleteCallback& callback) {
349 tilt_speed = std::min(tilt_speed, MAX_TILT_SPEED);
350 tilt_speed = tilt_speed > 0 ? tilt_speed : MAX_TILT_SPEED / 2;
351 tilt_ = value;
352 std::vector<char> command = kSetPanTiltCommand;
353 command[4] |= (MAX_PAN_SPEED / 2);
354 command[5] |= tilt_speed;
355 command[6] |= ((pan_ & 0xF000) >> 12);
356 command[7] |= ((pan_ & 0x0F00) >> 8);
357 command[8] |= ((pan_ & 0x00F0) >> 4);
358 command[9] |= (pan_ & 0x000F);
359 command[10] |= ((tilt_ & 0xF000) >> 12);
360 command[11] |= ((tilt_ & 0x0F00) >> 8);
361 command[12] |= ((tilt_ & 0x00F0) >> 4);
362 command[13] |= (tilt_ & 0x000F);
363 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
364 weak_ptr_factory_.GetWeakPtr(), callback));
367 void ViscaWebcam::SetZoom(int value, const SetPTZCompleteCallback& callback) {
368 std::vector<char> command = kSetZoomCommand;
369 command[4] |= ((value & 0xF000) >> 12);
370 command[5] |= ((value & 0x0F00) >> 8);
371 command[6] |= ((value & 0x00F0) >> 4);
372 command[7] |= (value & 0x000F);
373 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
374 weak_ptr_factory_.GetWeakPtr(), callback));
377 void ViscaWebcam::SetPanDirection(PanDirection direction,
378 int pan_speed,
379 const SetPTZCompleteCallback& callback) {
380 pan_speed = std::min(pan_speed, MAX_PAN_SPEED);
381 pan_speed = pan_speed > 0 ? pan_speed : MAX_PAN_SPEED / 2;
382 std::vector<char> command = kPTStopCommand;
383 switch (direction) {
384 case PAN_STOP:
385 break;
386 case PAN_RIGHT:
387 command = kPTRightCommand;
388 command[4] |= pan_speed;
389 command[5] |= (MAX_TILT_SPEED / 2);
390 break;
391 case PAN_LEFT:
392 command = kPTLeftCommand;
393 command[4] |= pan_speed;
394 command[5] |= (MAX_TILT_SPEED / 2);
395 break;
397 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
398 weak_ptr_factory_.GetWeakPtr(), callback));
401 void ViscaWebcam::SetTiltDirection(TiltDirection direction,
402 int tilt_speed,
403 const SetPTZCompleteCallback& callback) {
404 tilt_speed = std::min(tilt_speed, MAX_TILT_SPEED);
405 tilt_speed = tilt_speed > 0 ? tilt_speed : MAX_TILT_SPEED / 2;
406 std::vector<char> command = kPTStopCommand;
407 switch (direction) {
408 case TILT_STOP:
409 break;
410 case TILT_UP:
411 command = kPTUpCommand;
412 command[4] |= (MAX_PAN_SPEED / 2);
413 command[5] |= tilt_speed;
414 break;
415 case TILT_DOWN:
416 command = kPTDownCommand;
417 command[4] |= (MAX_PAN_SPEED / 2);
418 command[5] |= tilt_speed;
419 break;
421 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
422 weak_ptr_factory_.GetWeakPtr(), callback));
425 void ViscaWebcam::Reset(bool pan,
426 bool tilt,
427 bool zoom,
428 const SetPTZCompleteCallback& callback) {
429 // pan and tilt are always reset together in Visca Webcams.
430 if (pan || tilt) {
431 Send(kResetPanTiltCommand,
432 base::Bind(&ViscaWebcam::OnCommandCompleted,
433 weak_ptr_factory_.GetWeakPtr(), callback));
435 if (zoom) {
436 const int default_zoom = 1;
437 SetZoom(default_zoom, callback);
441 } // namespace extensions