UNPKG

visca-over-ip

Version:
278 lines 11.2 kB
"use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; exports.__esModule = true; exports.ViscaCamera = void 0; var buffer_1 = require("buffer"); var Command_1 = require("./Command"); var Constants_1 = require("./Constants"); var dgram = require('dgram'); var ViscaCamera = /** @class */ (function () { function ViscaCamera(ip, port) { var _this = this; this.ip = ip; this.port = port; this.connected = true; this.inquiryCallback = {}; this.inquiryQueue = []; this.sentCommands = []; this.commandQueue = []; this.events = {}; this.reconnect(); this.client.on('connect', function () { if (_this.connected == false) { _this.connected = true; _this.inquiryReady = true; _this.commandReady = true; if (_this.events.connected) _this.events.connected(); } }); this.client.on('close', function () { _this.connected = false; if (_this.events.closed) _this.events.closed(); }); this.client.on('message', function (data) { _this.connected = false; var command = Command_1.ViscaCommand.fromPacket(__spreadArray([], __read(data), false)); _this.onData(command); }); this.client.on('error', function (err) { _this.connected = false; if (_this.events.closed) _this.events.error(err); }); } //==================== Connectivity & Events ==================== ViscaCamera.prototype.on = function (eventType, handler) { if (eventType == 'connected' && this.events[eventType] == undefined && this.connected == true) handler(); this.events[eventType] = handler; }; ViscaCamera.prototype._handle = function (eventType) { var data = []; for (var _i = 1; _i < arguments.length; _i++) { data[_i - 1] = arguments[_i]; } if (this.events[eventType] != undefined) this.events[eventType](data); }; ViscaCamera.prototype.reconnect = function () { this.client = dgram.createSocket('udp4'); this.client.connect(this.port, this.ip, function () { }); }; //==================== Commands ==================== ViscaCamera.prototype.sendDirect = function (data) { var message = buffer_1.Buffer.from(data.toPacket()); this.client.send(message); }; ViscaCamera.prototype.sendCommand = function (command) { // this.sendRaw(command.toPacket()); this._updateBooleans(); command.addedAt = Date.now(); var queued = false; // INTERFACE_DATA, ADDRESS_SET commands always get sent and aren't tracked. // For inquiry commands, we need to keep track of them locally, so we can match replies to commands if (command.messageType == Constants_1.Constants.MSGTYPE_INQUIRY) { // only allow one non-ack command at a time if (this.inquiryReady) { this.inquiryCallback['0'] = command; // no ACK, only complete / error } else { this.inquiryQueue.push(command); queued = true; } } else if (command.messageType == Constants_1.Constants.MSGTYPE_COMMAND) { if (this.commandReady) { this.sentCommands.push(command); // not in a buffer until we get ACK } else { // this.commandQueue.push(command); this.sentCommands.push(command); // not in a buffer until we get ACK // queued = true; } } if (queued) { this._scheduleUpdate(); } else { command.sentAt = Date.now(); this.sendDirect(command); } }; //==================== Callback Handlers ==================== ViscaCamera.prototype.onData = function (viscaCommand) { switch (viscaCommand.messageType) { case Constants_1.Constants.MSGTYPE_IF_CLEAR: this._clear(); break; // network change messages are unprompted case Constants_1.Constants.MSGTYPE_NETCHANGE: // a camera issues this when it detects a change on the serial line, // and if we get it, we should re-assign all serial port cameras. // this.enumerateSerial(); break; // ack message, one of our commands was accepted and put in a buffer case Constants_1.Constants.MSGTYPE_ACK: this.ack(viscaCommand); return; // completion message case Constants_1.Constants.MSGTYPE_COMPLETE: this.complete(viscaCommand); break; // error messages case Constants_1.Constants.MSGTYPE_ERROR: this.error(viscaCommand); break; default: break; } // this.emit('update'); }; ViscaCamera.prototype.ack = function (viscaCommand) { // get the first viscaCommand that expects an ACK var _a = __read(this.sentCommands.splice(0, 1), 1), cmd = _a[0]; // gets the head if (cmd) { cmd._handle('ack'); // run the command ACK callback if it exists this.inquiryCallback[viscaCommand.socket] = cmd; } this._scheduleUpdate(); }; ViscaCamera.prototype.complete = function (viscaCommand) { var key = viscaCommand.socket.toString(); if (this.inquiryCallback[key] != undefined) { this.inquiryCallback[key]._handle('complete', viscaCommand.data); delete this.inquiryCallback[key]; } this._scheduleUpdate(); }; ViscaCamera.prototype.error = function (viscaCommand) { var message; var errorType = viscaCommand.data[0]; var socketKey = viscaCommand.socket.toString(); switch (errorType) { case Constants_1.Constants.ERROR_SYNTAX: message = "VISCA ERROR: syntax error, invalid command"; break; case Constants_1.Constants.ERROR_BUFFER_FULL: message = "VISCA ERROR: command buffers full"; break; case Constants_1.Constants.ERROR_CANCELLED: message = 'VISCA ERROR: command cancelled'; break; case Constants_1.Constants.ERROR_INVALID_BUFFER: message = "VISCA ERROR: socket cannot be cancelled"; break; case Constants_1.Constants.ERROR_COMMAND_FAILED: message = "VISCA ERROR: command failed"; break; } if (this.inquiryCallback[socketKey]) { this.inquiryCallback[socketKey]._handle('error', new Error(message)); } else { this._handle('error', new Error(message)); } delete this.inquiryCallback[socketKey]; this._update(); }; //==================== Private Functions ==================== ViscaCamera.prototype._clear = function () { this.inquiryCallback = {}; this.sentCommands = []; }; ViscaCamera.prototype._updateBooleans = function () { this.commandReady = !('1' in this.inquiryCallback || '2' in this.inquiryCallback); this.inquiryReady = !('0' in this.inquiryCallback); }; ViscaCamera.prototype._scheduleUpdate = function () { var _this = this; if (this.updateTimeout != null) return; if (this.inquiryQueue.length > 0 || this.commandQueue.length > 0) { this.updateTimeout = setTimeout(function () { return _this._update(); }, 25); } }; ViscaCamera.prototype._update = function () { this.updateTimeout = null; this._expireOldCommands(); this._processQueue(); // this.emit('update'); }; ViscaCamera.prototype._processQueue = function () { this._updateBooleans(); if (this.commandReady && this.commandQueue.length > 0) { var _a = __read(this.commandQueue.splice(0, 1), 1), cmd = _a[0]; this.sendCommand(cmd); } if (this.inquiryReady && this.inquiryQueue.length > 0) { var _b = __read(this.inquiryQueue.splice(0, 1), 1), cmd = _b[0]; this.sendCommand(cmd); } this._updateBooleans(); }; ViscaCamera.prototype._expireOldCommands = function () { var e_1, _a; var now = Date.now(); // the first command is always the oldest while (this.sentCommands.length > 0) { if (now - this.sentCommands[0].sentAt < Constants_1.Constants.COMMAND_TIMEOUT) break; this.sentCommands.splice(0, 1); } try { // check all cameraBuffers for (var _b = __values(Object.keys(this.inquiryCallback)), _c = _b.next(); !_c.done; _c = _b.next()) { var key = _c.value; if (now - this.inquiryCallback[key].sentAt > Constants_1.Constants.COMMAND_TIMEOUT) delete this.inquiryCallback[key]; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); } finally { if (e_1) throw e_1.error; } } }; return ViscaCamera; }()); exports.ViscaCamera = ViscaCamera; //# sourceMappingURL=Camera.js.map