UNPKG

homebridge-plugin-wrapper

Version:

Wrapper for Homebridge and NodeJS-HAP with reduced dependencies that allows to intercept plugin values and also send to them

715 lines 34.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CameraController = exports.CameraControllerEvents = exports.ResourceRequestReason = void 0; var tslib_1 = require("tslib"); var crypto_1 = (0, tslib_1.__importDefault)(require("crypto")); var debug_1 = (0, tslib_1.__importDefault)(require("debug")); var events_1 = require("events"); var camera_1 = require("../camera"); var Characteristic_1 = require("../Characteristic"); var datastream_1 = require("../datastream"); var Service_1 = require("../Service"); var hapStatusError_1 = require("../util/hapStatusError"); var debug = (0, debug_1.default)("HAP-NodeJS:Camera:Controller"); var ResourceRequestReason; (function (ResourceRequestReason) { /** * The reason describes periodic resource requests. * In the example of camera image snapshots those are the typical preview images every 10 seconds. */ ResourceRequestReason[ResourceRequestReason["PERIODIC"] = 0] = "PERIODIC"; /** * The resource request is the result of some event. * In the example of camera image snapshots, requests are made due to e.g. a motion event or similar. */ ResourceRequestReason[ResourceRequestReason["EVENT"] = 1] = "EVENT"; })(ResourceRequestReason = exports.ResourceRequestReason || (exports.ResourceRequestReason = {})); var CameraControllerEvents; (function (CameraControllerEvents) { /** * Emitted when the mute state or the volume changed. The Apple Home App typically does not set those values * except the mute state. When you adjust the volume in the Camera view it will reset the muted state if it was set previously. * The value of volume has nothing to do with the volume slider in the Camera view of the Home app. */ CameraControllerEvents["MICROPHONE_PROPERTIES_CHANGED"] = "microphone-change"; /** * Emitted when the mute state or the volume changed. The Apple Home App typically does not set those values * except the mute state. When you unmute the device microphone it will reset the mute state if it was set previously. */ CameraControllerEvents["SPEAKER_PROPERTIES_CHANGED"] = "speaker-change"; })(CameraControllerEvents = exports.CameraControllerEvents || (exports.CameraControllerEvents = {})); /** * Everything needed to expose a HomeKit Camera. */ var CameraController = /** @class */ (function (_super) { (0, tslib_1.__extends)(CameraController, _super); function CameraController(options, legacyMode) { if (legacyMode === void 0) { legacyMode = false; } var _this = _super.call(this) || this; _this.legacyMode = false; /** * @private */ _this.streamManagements = []; _this.microphoneMuted = false; _this.microphoneVolume = 100; _this.speakerMuted = false; _this.speakerVolume = 100; _this.motionServiceExternallySupplied = false; _this.occupancyServiceExternallySupplied = false; _this.streamCount = Math.max(1, options.cameraStreamCount || 1); _this.delegate = options.delegate; _this.streamingOptions = options.streamingOptions; _this.recording = options.recording; _this.sensorOptions = options.sensors; _this.legacyMode = legacyMode; // legacy mode will prevent from Microphone and Speaker services to get created to avoid collisions return _this; } /** * @private */ CameraController.prototype.controllerId = function () { return "camera" /* CAMERA */; }; // ----------------------------------- STREAM API ------------------------------------ /** * Call this method if you want to forcefully suspend an ongoing streaming session. * This would be adequate if the rtp server or media encoding encountered an unexpected error. * * @param sessionId {SessionIdentifier} - id of the current ongoing streaming session */ CameraController.prototype.forceStopStreamingSession = function (sessionId) { this.streamManagements.forEach(function (management) { if (management.sessionIdentifier === sessionId) { management.forceStop(); } }); }; CameraController.generateSynchronisationSource = function () { var ssrc = crypto_1.default.randomBytes(4); // range [-2.14748e+09 - 2.14748e+09] ssrc[0] = 0; return ssrc.readInt32BE(0); }; // ----------------------------- MICROPHONE/SPEAKER API ------------------------------ CameraController.prototype.setMicrophoneMuted = function (muted) { if (muted === void 0) { muted = true; } if (!this.microphoneService) { return; } this.microphoneMuted = muted; this.microphoneService.updateCharacteristic(Characteristic_1.Characteristic.Mute, muted); }; CameraController.prototype.setMicrophoneVolume = function (volume) { if (!this.microphoneService) { return; } this.microphoneVolume = volume; this.microphoneService.updateCharacteristic(Characteristic_1.Characteristic.Volume, volume); }; CameraController.prototype.setSpeakerMuted = function (muted) { if (muted === void 0) { muted = true; } if (!this.speakerService) { return; } this.speakerMuted = muted; this.speakerService.updateCharacteristic(Characteristic_1.Characteristic.Mute, muted); }; CameraController.prototype.setSpeakerVolume = function (volume) { if (!this.speakerService) { return; } this.speakerVolume = volume; this.speakerService.updateCharacteristic(Characteristic_1.Characteristic.Volume, volume); }; CameraController.prototype.emitMicrophoneChange = function () { this.emit("microphone-change" /* MICROPHONE_PROPERTIES_CHANGED */, this.microphoneMuted, this.microphoneVolume); }; CameraController.prototype.emitSpeakerChange = function () { this.emit("speaker-change" /* SPEAKER_PROPERTIES_CHANGED */, this.speakerMuted, this.speakerVolume); }; // ----------------------------------------------------------------------------------- /** * @private */ CameraController.prototype.constructServices = function () { var _a, _b, _c, _d; for (var i = 0; i < this.streamCount; i++) { var rtp = new camera_1.RTPStreamManagement(i, this.streamingOptions, this.delegate, undefined, this.rtpStreamManagementDisabledThroughOperatingMode.bind(this)); this.streamManagements.push(rtp); } if (!this.legacyMode && this.streamingOptions.audio) { // In theory the Microphone Service is a necessity. In practice, it's not. lol. // So we just add it if the user wants to support audio this.microphoneService = new Service_1.Service.Microphone("", ""); this.microphoneService.setCharacteristic(Characteristic_1.Characteristic.Volume, this.microphoneVolume); if (this.streamingOptions.audio.twoWayAudio) { this.speakerService = new Service_1.Service.Speaker("", ""); this.speakerService.setCharacteristic(Characteristic_1.Characteristic.Volume, this.speakerVolume); } } if (this.recording) { this.recordingManagement = new camera_1.RecordingManagement(this.recording.options, this.recording.delegate, this.retrieveEventTriggerOptions()); } if ((_a = this.sensorOptions) === null || _a === void 0 ? void 0 : _a.motion) { if (typeof this.sensorOptions.motion === "boolean") { this.motionService = new Service_1.Service.MotionSensor("", ""); } else { this.motionService = this.sensorOptions.motion; this.motionServiceExternallySupplied = true; } this.motionService.setCharacteristic(Characteristic_1.Characteristic.StatusActive, true); (_b = this.recordingManagement) === null || _b === void 0 ? void 0 : _b.recordingManagementService.addLinkedService(this.motionService); } if ((_c = this.sensorOptions) === null || _c === void 0 ? void 0 : _c.occupancy) { if (typeof this.sensorOptions.occupancy === "boolean") { this.occupancyService = new Service_1.Service.OccupancySensor("", ""); } else { this.occupancyService = this.sensorOptions.occupancy; this.occupancyServiceExternallySupplied = true; } this.occupancyService.setCharacteristic(Characteristic_1.Characteristic.StatusActive, true); (_d = this.recordingManagement) === null || _d === void 0 ? void 0 : _d.recordingManagementService.addLinkedService(this.occupancyService); } var serviceMap = { microphone: this.microphoneService, speaker: this.speakerService, motionService: !this.motionServiceExternallySupplied ? this.motionService : undefined, occupancyService: !this.occupancyServiceExternallySupplied ? this.occupancyService : undefined, }; if (this.recordingManagement) { serviceMap.cameraEventRecordingManagement = this.recordingManagement.recordingManagementService; serviceMap.cameraOperatingMode = this.recordingManagement.operatingModeService; serviceMap.dataStreamTransportManagement = this.recordingManagement.dataStreamManagement.getService(); } this.streamManagements.forEach(function (management, index) { serviceMap[CameraController.STREAM_MANAGEMENT + index] = management.getService(); }); this.recording = undefined; this.sensorOptions = undefined; return serviceMap; }; /** * @private */ CameraController.prototype.initWithServices = function (serviceMap) { var result = this._initWithServices(serviceMap); if (result.updated) { // serviceMap must only be returned if anything actually changed return result.serviceMap; } }; CameraController.prototype._initWithServices = function (serviceMap) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; var modifiedServiceMap = false; // eslint-disable-next-line no-constant-condition for (var i = 0; true; i++) { var streamManagementService = serviceMap[CameraController.STREAM_MANAGEMENT + i]; if (i < this.streamCount) { var operatingModeClosure = this.rtpStreamManagementDisabledThroughOperatingMode.bind(this); if (streamManagementService) { // normal init this.streamManagements.push(new camera_1.RTPStreamManagement(i, this.streamingOptions, this.delegate, streamManagementService, operatingModeClosure)); } else { // stream count got bigger, we need to create a new service var management = new camera_1.RTPStreamManagement(i, this.streamingOptions, this.delegate, undefined, operatingModeClosure); this.streamManagements.push(management); serviceMap[CameraController.STREAM_MANAGEMENT + i] = management.getService(); modifiedServiceMap = true; } } else { if (streamManagementService) { // stream count got reduced, we need to remove old service delete serviceMap[CameraController.STREAM_MANAGEMENT + i]; modifiedServiceMap = true; } else { break; // we finished counting, and we got no saved service; we are finished } } } // MICROPHONE if (!this.legacyMode && this.streamingOptions.audio) { // microphone should be present if (serviceMap.microphone) { this.microphoneService = serviceMap.microphone; } else { // microphone wasn't created yet => create a new one this.microphoneService = new Service_1.Service.Microphone("", ""); this.microphoneService.setCharacteristic(Characteristic_1.Characteristic.Volume, this.microphoneVolume); serviceMap.microphone = this.microphoneService; modifiedServiceMap = true; } } else if (serviceMap.microphone) { // microphone service supplied, though settings seemed to have changed // we need to remove it delete serviceMap.microphone; modifiedServiceMap = true; } // SPEAKER if (!this.legacyMode && ((_a = this.streamingOptions.audio) === null || _a === void 0 ? void 0 : _a.twoWayAudio)) { // speaker should be present if (serviceMap.speaker) { this.speakerService = serviceMap.speaker; } else { // speaker wasn't created yet => create a new one this.speakerService = new Service_1.Service.Speaker("", ""); this.speakerService.setCharacteristic(Characteristic_1.Characteristic.Volume, this.speakerVolume); serviceMap.speaker = this.speakerService; modifiedServiceMap = true; } } else if (serviceMap.speaker) { // speaker service supplied, though settings seemed to have changed // we need to remove it delete serviceMap.speaker; modifiedServiceMap = true; } // RECORDING if (this.recording) { var eventTriggers = this.retrieveEventTriggerOptions(); // RECORDING MANAGEMENT if (serviceMap.cameraEventRecordingManagement && serviceMap.cameraOperatingMode && serviceMap.dataStreamTransportManagement) { this.recordingManagement = new camera_1.RecordingManagement(this.recording.options, this.recording.delegate, eventTriggers, { recordingManagement: serviceMap.cameraEventRecordingManagement, operatingMode: serviceMap.cameraOperatingMode, dataStreamManagement: new datastream_1.DataStreamManagement(serviceMap.dataStreamTransportManagement), }); } else { this.recordingManagement = new camera_1.RecordingManagement(this.recording.options, this.recording.delegate, eventTriggers); serviceMap.cameraEventRecordingManagement = this.recordingManagement.recordingManagementService; serviceMap.cameraOperatingMode = this.recordingManagement.operatingModeService; serviceMap.dataStreamTransportManagement = this.recordingManagement.dataStreamManagement.getService(); modifiedServiceMap = true; } } else { if (serviceMap.cameraEventRecordingManagement) { delete serviceMap.cameraEventRecordingManagement; modifiedServiceMap = true; } if (serviceMap.cameraOperatingMode) { delete serviceMap.cameraOperatingMode; modifiedServiceMap = true; } if (serviceMap.dataStreamTransportManagement) { delete serviceMap.dataStreamTransportManagement; modifiedServiceMap = true; } } // MOTION SENSOR if ((_b = this.sensorOptions) === null || _b === void 0 ? void 0 : _b.motion) { if (typeof this.sensorOptions.motion === "boolean") { if (serviceMap.motionService) { this.motionService = serviceMap.motionService; } else { // it could be the case that we previously had a manually supplied motion service // at this point we can't remove the iid from the list of linked services from the recording management! this.motionService = new Service_1.Service.MotionSensor("", ""); } } else { this.motionService = this.sensorOptions.motion; this.motionServiceExternallySupplied = true; if (serviceMap.motionService) { // motion service previously supplied as bool option (_c = this.recordingManagement) === null || _c === void 0 ? void 0 : _c.recordingManagementService.removeLinkedService(serviceMap.motionService); delete serviceMap.motionService; modifiedServiceMap = true; } } this.motionService.setCharacteristic(Characteristic_1.Characteristic.StatusActive, true); (_d = this.recordingManagement) === null || _d === void 0 ? void 0 : _d.recordingManagementService.addLinkedService(this.motionService); } else { if (serviceMap.motionService) { (_e = this.recordingManagement) === null || _e === void 0 ? void 0 : _e.recordingManagementService.removeLinkedService(serviceMap.motionService); delete serviceMap.motionService; modifiedServiceMap = true; } } // OCCUPANCY SENSOR if ((_f = this.sensorOptions) === null || _f === void 0 ? void 0 : _f.occupancy) { if (typeof this.sensorOptions.occupancy === "boolean") { if (serviceMap.occupancyService) { this.occupancyService = serviceMap.occupancyService; } else { // it could be the case that we previously had a manually supplied occupancy service // at this point we can't remove the iid from the list of linked services from the recording management! this.occupancyService = new Service_1.Service.OccupancySensor("", ""); } } else { this.occupancyService = this.sensorOptions.occupancy; this.occupancyServiceExternallySupplied = true; if (serviceMap.occupancyService) { // occupancy service previously supplied as bool option (_g = this.recordingManagement) === null || _g === void 0 ? void 0 : _g.recordingManagementService.removeLinkedService(serviceMap.occupancyService); delete serviceMap.occupancyService; modifiedServiceMap = true; } } this.occupancyService.setCharacteristic(Characteristic_1.Characteristic.StatusActive, true); (_h = this.recordingManagement) === null || _h === void 0 ? void 0 : _h.recordingManagementService.addLinkedService(this.occupancyService); } else { if (serviceMap.occupancyService) { (_j = this.recordingManagement) === null || _j === void 0 ? void 0 : _j.recordingManagementService.removeLinkedService(serviceMap.occupancyService); delete serviceMap.occupancyService; modifiedServiceMap = true; } } if (this.migrateFromDoorbell(serviceMap)) { modifiedServiceMap = true; } this.recording = undefined; this.sensorOptions = undefined; return { serviceMap: serviceMap, updated: modifiedServiceMap, }; }; // overwritten in DoorbellController (to avoid cyclic dependencies, I hate typescript for that) CameraController.prototype.migrateFromDoorbell = function (serviceMap) { if (serviceMap.doorbell) { // See NOTICE in DoorbellController delete serviceMap.doorbell; return true; } return false; }; CameraController.prototype.retrieveEventTriggerOptions = function () { var e_1, _a; var _b; if (!this.recording) { return new Set(); } var triggerOptions = new Set(); if (this.recording.options.overrideEventTriggerOptions) { try { for (var _c = (0, tslib_1.__values)(this.recording.options.overrideEventTriggerOptions), _d = _c.next(); !_d.done; _d = _c.next()) { var option = _d.value; triggerOptions.add(option); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_1) throw e_1.error; } } } if ((_b = this.sensorOptions) === null || _b === void 0 ? void 0 : _b.motion) { triggerOptions.add(1 /* MOTION */); } // this method is overwritten by the `DoorbellController` to automatically configure EventTriggerOption.DOORBELL return triggerOptions; }; /** * @private */ CameraController.prototype.configureServices = function () { var _this = this; var _a, _b; if (this.microphoneService) { this.microphoneService.getCharacteristic(Characteristic_1.Characteristic.Mute) .on("get" /* GET */, function (callback) { callback(undefined, _this.microphoneMuted); }) .on("set" /* SET */, function (value, callback) { _this.microphoneMuted = value; callback(); _this.emitMicrophoneChange(); }); this.microphoneService.getCharacteristic(Characteristic_1.Characteristic.Volume) .on("get" /* GET */, function (callback) { callback(undefined, _this.microphoneVolume); }) .on("set" /* SET */, function (value, callback) { _this.microphoneVolume = value; callback(); _this.emitMicrophoneChange(); }); } if (this.speakerService) { this.speakerService.getCharacteristic(Characteristic_1.Characteristic.Mute) .on("get" /* GET */, function (callback) { callback(undefined, _this.speakerMuted); }) .on("set" /* SET */, function (value, callback) { _this.speakerMuted = value; callback(); _this.emitSpeakerChange(); }); this.speakerService.getCharacteristic(Characteristic_1.Characteristic.Volume) .on("get" /* GET */, function (callback) { callback(undefined, _this.speakerVolume); }) .on("set" /* SET */, function (value, callback) { _this.speakerVolume = value; callback(); _this.emitSpeakerChange(); }); } // make the sensor services available to the RecordingManagement. if (this.motionService) { (_a = this.recordingManagement) === null || _a === void 0 ? void 0 : _a.sensorServices.push(this.motionService); } if (this.occupancyService) { (_b = this.recordingManagement) === null || _b === void 0 ? void 0 : _b.sensorServices.push(this.occupancyService); } }; CameraController.prototype.rtpStreamManagementDisabledThroughOperatingMode = function () { return this.recordingManagement ? !this.recordingManagement.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive).value : false; }; /** * @private */ CameraController.prototype.handleControllerRemoved = function () { var e_2, _a; var _b; this.handleFactoryReset(); try { for (var _c = (0, tslib_1.__values)(this.streamManagements), _d = _c.next(); !_d.done; _d = _c.next()) { var management = _d.value; management.destroy(); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_2) throw e_2.error; } } this.streamManagements.splice(0, this.streamManagements.length); this.microphoneService = undefined; this.speakerService = undefined; (_b = this.recordingManagement) === null || _b === void 0 ? void 0 : _b.destroy(); this.recordingManagement = undefined; this.removeAllListeners(); }; /** * @private */ CameraController.prototype.handleFactoryReset = function () { var _a; this.streamManagements.forEach(function (management) { return management.handleFactoryReset(); }); (_a = this.recordingManagement) === null || _a === void 0 ? void 0 : _a.handleFactoryReset(); this.microphoneMuted = false; this.microphoneVolume = 100; this.speakerMuted = false; this.speakerVolume = 100; }; /** * @private */ CameraController.prototype.serialize = function () { var e_3, _a; var _b; var streamManagementStates = []; try { for (var _c = (0, tslib_1.__values)(this.streamManagements), _d = _c.next(); !_d.done; _d = _c.next()) { var management = _d.value; var serializedState = management.serialize(); if (serializedState) { streamManagementStates.push(serializedState); } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_3) throw e_3.error; } } return { streamManagements: streamManagementStates, recordingManagement: (_b = this.recordingManagement) === null || _b === void 0 ? void 0 : _b.serialize(), }; }; /** * @private */ CameraController.prototype.deserialize = function (serialized) { var e_4, _a, e_5, _b; var _c; try { for (var _d = (0, tslib_1.__values)(serialized.streamManagements), _e = _d.next(); !_e.done; _e = _d.next()) { var streamManagementState = _e.value; var streamManagement = this.streamManagements[streamManagementState.id]; if (streamManagement) { streamManagement.deserialize(streamManagementState); } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_e && !_e.done && (_a = _d.return)) _a.call(_d); } finally { if (e_4) throw e_4.error; } } if (serialized.recordingManagement) { if (this.recordingManagement) { this.recordingManagement.deserialize(serialized.recordingManagement); } else { try { // Active characteristic cannot be controlled if removing HSV, ensure they are all active! for (var _f = (0, tslib_1.__values)(this.streamManagements), _g = _f.next(); !_g.done; _g = _f.next()) { var streamManagement = _g.value; streamManagement.service.updateCharacteristic(Characteristic_1.Characteristic.Active, true); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (_g && !_g.done && (_b = _f.return)) _b.call(_f); } finally { if (e_5) throw e_5.error; } } (_c = this.stateChangeDelegate) === null || _c === void 0 ? void 0 : _c.call(this); } } }; /** * @private */ CameraController.prototype.setupStateChangeDelegate = function (delegate) { var e_6, _a; var _b; this.stateChangeDelegate = delegate; try { for (var _c = (0, tslib_1.__values)(this.streamManagements), _d = _c.next(); !_d.done; _d = _c.next()) { var streamManagement = _d.value; streamManagement.setupStateChangeDelegate(delegate); } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_6) throw e_6.error; } } (_b = this.recordingManagement) === null || _b === void 0 ? void 0 : _b.setupStateChangeDelegate(delegate); }; /** * @private */ CameraController.prototype.handleSnapshotRequest = function (height, width, accessoryName, reason) { var _this = this; // first step is to verify that the reason is applicable to our current policy var streamingDisabled = this.streamManagements .map(function (management) { return !management.getService().getCharacteristic(Characteristic_1.Characteristic.Active).value; }) .reduce(function (previousValue, currentValue) { return previousValue && currentValue; }); if (streamingDisabled) { debug("[%s] Rejecting snapshot as streaming is disabled.", accessoryName); return Promise.reject(-70412 /* NOT_ALLOWED_IN_CURRENT_STATE */); } if (this.recordingManagement) { var operatingModeService = this.recordingManagement.operatingModeService; if (!operatingModeService.getCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive).value) { debug("[%s] Rejecting snapshot as HomeKit camera is disabled.", accessoryName); return Promise.reject(-70412 /* NOT_ALLOWED_IN_CURRENT_STATE */); } var eventSnapshotsActive = operatingModeService .getCharacteristic(Characteristic_1.Characteristic.EventSnapshotsActive) .value; if (!eventSnapshotsActive) { if (reason == null) { debug("[%s] Rejecting snapshot as reason is required due to disabled event snapshots.", accessoryName); return Promise.reject(-70401 /* INSUFFICIENT_PRIVILEGES */); } else if (reason === 1 /* EVENT */) { debug("[%s] Rejecting snapshot as even snapshots are disabled.", accessoryName); return Promise.reject(-70412 /* NOT_ALLOWED_IN_CURRENT_STATE */); } } var periodicSnapshotsActive = operatingModeService .getCharacteristic(Characteristic_1.Characteristic.PeriodicSnapshotsActive) .value; if (!periodicSnapshotsActive) { if (reason == null) { debug("[%s] Rejecting snapshot as reason is required due to disabled periodic snapshots.", accessoryName); return Promise.reject(-70401 /* INSUFFICIENT_PRIVILEGES */); } else if (reason === 0 /* PERIODIC */) { debug("[%s] Rejecting snapshot as periodic snapshots are disabled.", accessoryName); return Promise.reject(-70412 /* NOT_ALLOWED_IN_CURRENT_STATE */); } } } // now do the actual snapshot request. return new Promise(function (resolve, reject) { var timeout = setTimeout(function () { console.warn("[".concat(accessoryName, "] The image snapshot handler for the given accessory is slow to respond! See https://homebridge.io/w/JtMGR for more info.")); timeout = setTimeout(function () { timeout = undefined; console.warn("[".concat(accessoryName, "] The image snapshot handler for the given accessory didn't respond at all! See https://homebridge.io/w/JtMGR for more info.")); reject(-70408 /* OPERATION_TIMED_OUT */); }, 17000); timeout.unref(); }, 5000); timeout.unref(); try { _this.delegate.handleSnapshotRequest({ height: height, width: width, reason: reason, }, function (error, buffer) { if (!timeout) { return; } else { clearTimeout(timeout); timeout = undefined; } if (error) { if (typeof error === "number") { reject(error); } else { debug("[%s] Error getting snapshot: %s", accessoryName, error.stack); reject(-70402 /* SERVICE_COMMUNICATION_FAILURE */); } return; } if (!buffer || buffer.length === 0) { console.warn("[".concat(accessoryName, "] Snapshot request handler provided empty image buffer!")); reject(-70402 /* SERVICE_COMMUNICATION_FAILURE */); } else { resolve(buffer); } }); } catch (error) { if (!timeout) { return; } else { clearTimeout(timeout); timeout = undefined; } console.warn("[".concat(accessoryName, "] Unhandled error thrown inside snapshot request handler: ").concat(error.stack)); reject(error instanceof hapStatusError_1.HapStatusError ? error.hapStatus : -70402 /* SERVICE_COMMUNICATION_FAILURE */); } }); }; /** * @private */ CameraController.prototype.handleCloseConnection = function (sessionID) { if (this.delegate instanceof camera_1.LegacyCameraSourceAdapter) { this.delegate.forwardCloseConnection(sessionID); } }; CameraController.STREAM_MANAGEMENT = "streamManagement"; // key to index all RTPStreamManagement services return CameraController; }(events_1.EventEmitter)); exports.CameraController = CameraController; //# sourceMappingURL=CameraController.js.map