hap-nodejs 1.1.0 → 1.1.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/bonjour-hap.d.ts +50 -53
- package/README.md +16 -19
- package/dist/accessories/AirConditioner_accessory.js +28 -30
- package/dist/accessories/AirConditioner_accessory.js.map +1 -1
- package/dist/accessories/AppleTVRemote_accessory.js +69 -81
- package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
- package/dist/accessories/Camera_accessory.js +159 -144
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +18 -22
- package/dist/accessories/Fan_accessory.js.map +1 -1
- package/dist/accessories/GarageDoorOpener_accessory.js +33 -35
- package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
- package/dist/accessories/Light-AdaptiveLighting_accessory.js +42 -44
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +32 -34
- package/dist/accessories/Light_accessory.js.map +1 -1
- package/dist/accessories/Lock_accessory.js +25 -26
- package/dist/accessories/Lock_accessory.js.map +1 -1
- package/dist/accessories/MotionSensor_accessory.js +13 -16
- package/dist/accessories/MotionSensor_accessory.js.map +1 -1
- package/dist/accessories/Outlet_accessory.js +20 -22
- package/dist/accessories/Outlet_accessory.js.map +1 -1
- package/dist/accessories/SmartSpeaker_accessory.js +18 -20
- package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
- package/dist/accessories/Sprinkler_accessory.js +34 -37
- package/dist/accessories/Sprinkler_accessory.js.map +1 -1
- package/dist/accessories/TV_accessory.js +43 -45
- package/dist/accessories/TV_accessory.js.map +1 -1
- package/dist/accessories/TemperatureSensor_accessory.js +12 -15
- package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.d.ts +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.d.ts.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.js +9 -12
- package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.d.ts +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.d.ts.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.js +11 -14
- package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.d.ts +3 -3
- package/dist/accessories/gstreamer-audioProducer.d.ts.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.js +45 -46
- package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
- package/dist/accessories/types.d.ts +63 -63
- package/dist/accessories/types.d.ts.map +1 -1
- package/dist/accessories/types.js +83 -87
- package/dist/accessories/types.js.map +1 -1
- package/dist/index.d.ts +26 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -34
- package/dist/index.js.map +1 -1
- package/dist/internal-types.d.ts +1 -1
- package/dist/internal-types.d.ts.map +1 -1
- package/dist/internal-types.js +19 -21
- package/dist/internal-types.js.map +1 -1
- package/dist/lib/Accessory.d.ts +39 -38
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +313 -296
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/Advertiser.d.ts +16 -13
- package/dist/lib/Advertiser.d.ts.map +1 -1
- package/dist/lib/Advertiser.js +147 -153
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.d.ts +1 -1
- package/dist/lib/Bridge.d.ts.map +1 -1
- package/dist/lib/Bridge.js +2 -6
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.d.ts +48 -69
- package/dist/lib/Characteristic.d.ts.map +1 -1
- package/dist/lib/Characteristic.js +212 -236
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.d.ts +31 -30
- package/dist/lib/HAPServer.d.ts.map +1 -1
- package/dist/lib/HAPServer.js +220 -229
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.d.ts +22 -30
- package/dist/lib/Service.d.ts.map +1 -1
- package/dist/lib/Service.js +63 -75
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/RTPProxy.d.ts +2 -1
- package/dist/lib/camera/RTPProxy.d.ts.map +1 -1
- package/dist/lib/camera/RTPProxy.js +28 -44
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.d.ts +34 -33
- package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +181 -149
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.d.ts +19 -17
- package/dist/lib/camera/RecordingManagement.d.ts.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +160 -151
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.d.ts +3 -3
- package/dist/lib/camera/index.d.ts.map +1 -1
- package/dist/lib/camera/index.js +3 -6
- package/dist/lib/camera/index.js.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.d.ts +33 -33
- package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +152 -144
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.d.ts +22 -20
- package/dist/lib/controller/CameraController.d.ts.map +1 -1
- package/dist/lib/controller/CameraController.js +74 -78
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/Controller.d.ts +4 -4
- package/dist/lib/controller/Controller.d.ts.map +1 -1
- package/dist/lib/controller/Controller.js +5 -8
- package/dist/lib/controller/Controller.js.map +1 -1
- package/dist/lib/controller/DoorbellController.d.ts +5 -4
- package/dist/lib/controller/DoorbellController.d.ts.map +1 -1
- package/dist/lib/controller/DoorbellController.js +9 -13
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.d.ts +39 -37
- package/dist/lib/controller/RemoteController.d.ts.map +1 -1
- package/dist/lib/controller/RemoteController.js +208 -197
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.d.ts +5 -5
- package/dist/lib/controller/index.d.ts.map +1 -1
- package/dist/lib/controller/index.js +5 -8
- package/dist/lib/controller/index.js.map +1 -1
- package/dist/lib/datastream/DataStreamManagement.d.ts +2 -2
- package/dist/lib/datastream/DataStreamManagement.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +39 -39
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.d.ts +1 -0
- package/dist/lib/datastream/DataStreamParser.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +57 -77
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts +23 -22
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +154 -164
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.d.ts +3 -3
- package/dist/lib/datastream/index.d.ts.map +1 -1
- package/dist/lib/datastream/index.js +3 -6
- package/dist/lib/datastream/index.js.map +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts +15 -60
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +978 -1317
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.d.ts +1 -15
- package/dist/lib/definitions/ServiceDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +621 -726
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.d.ts +3 -3
- package/dist/lib/definitions/generate-definitions.d.ts.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +246 -251
- package/dist/lib/definitions/generate-definitions.js.map +1 -1
- package/dist/lib/definitions/generator-configuration.d.ts +1 -1
- package/dist/lib/definitions/generator-configuration.d.ts.map +1 -1
- package/dist/lib/definitions/generator-configuration.js +160 -354
- package/dist/lib/definitions/generator-configuration.js.map +1 -1
- package/dist/lib/definitions/index.d.ts +2 -2
- package/dist/lib/definitions/index.d.ts.map +1 -1
- package/dist/lib/definitions/index.js +2 -5
- package/dist/lib/definitions/index.js.map +1 -1
- package/dist/lib/model/AccessoryInfo.d.ts +4 -3
- package/dist/lib/model/AccessoryInfo.d.ts.map +1 -1
- package/dist/lib/model/AccessoryInfo.js +50 -53
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.d.ts +3 -3
- package/dist/lib/model/ControllerStorage.d.ts.map +1 -1
- package/dist/lib/model/ControllerStorage.js +18 -23
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.d.ts +2 -2
- package/dist/lib/model/HAPStorage.d.ts.map +1 -1
- package/dist/lib/model/HAPStorage.js +4 -11
- package/dist/lib/model/HAPStorage.js.map +1 -1
- package/dist/lib/model/IdentifierCache.d.ts +1 -1
- package/dist/lib/model/IdentifierCache.d.ts.map +1 -1
- package/dist/lib/model/IdentifierCache.js +19 -27
- package/dist/lib/model/IdentifierCache.js.map +1 -1
- package/dist/lib/tv/AccessControlManagement.d.ts +9 -9
- package/dist/lib/tv/AccessControlManagement.d.ts.map +1 -1
- package/dist/lib/tv/AccessControlManagement.js +27 -29
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/checkName.d.ts +2 -2
- package/dist/lib/util/checkName.d.ts.map +1 -1
- package/dist/lib/util/checkName.js +6 -9
- package/dist/lib/util/checkName.js.map +1 -1
- package/dist/lib/util/clone.d.ts.map +1 -1
- package/dist/lib/util/clone.js +1 -5
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.d.ts +1 -1
- package/dist/lib/util/color-utils.d.ts.map +1 -1
- package/dist/lib/util/color-utils.js +4 -9
- package/dist/lib/util/color-utils.js.map +1 -1
- package/dist/lib/util/eventedhttp.d.ts +23 -22
- package/dist/lib/util/eventedhttp.d.ts.map +1 -1
- package/dist/lib/util/eventedhttp.js +109 -116
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.d.ts +3 -2
- package/dist/lib/util/hapCrypto.d.ts.map +1 -1
- package/dist/lib/util/hapCrypto.js +31 -40
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.d.ts +1 -1
- package/dist/lib/util/hapStatusError.d.ts.map +1 -1
- package/dist/lib/util/hapStatusError.js +4 -8
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.d.ts +1 -1
- package/dist/lib/util/net-utils.js +17 -23
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.d.ts.map +1 -1
- package/dist/lib/util/once.js +2 -6
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.d.ts +1 -1
- package/dist/lib/util/promise-utils.d.ts.map +1 -1
- package/dist/lib/util/promise-utils.js +3 -10
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.d.ts +3 -2
- package/dist/lib/util/request-util.d.ts.map +1 -1
- package/dist/lib/util/request-util.js +11 -19
- package/dist/lib/util/request-util.js.map +1 -1
- package/dist/lib/util/time.d.ts +1 -0
- package/dist/lib/util/time.d.ts.map +1 -1
- package/dist/lib/util/time.js +6 -11
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/tlv.d.ts +1 -0
- package/dist/lib/util/tlv.d.ts.map +1 -1
- package/dist/lib/util/tlv.js +28 -43
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.d.ts +1 -0
- package/dist/lib/util/uuid.d.ts.map +1 -1
- package/dist/lib/util/uuid.js +26 -38
- package/dist/lib/util/uuid.js.map +1 -1
- package/dist/types.d.ts +24 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -5
- package/dist/types.js.map +1 -1
- package/package.json +49 -47
- package/@types/simple-plist.d.ts +0 -4
- package/dist/lib/gen/HomeKit.d.ts +0 -7
- package/dist/lib/gen/HomeKit.d.ts.map +0 -1
- package/dist/lib/gen/HomeKit.js +0 -8
- package/dist/lib/gen/HomeKit.js.map +0 -1
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const hapStatusError_1 = require("../util/hapStatusError");
|
|
12
|
-
const tlv = tslib_1.__importStar(require("../util/tlv"));
|
|
13
|
-
const debug = (0, debug_1.default)("HAP-NodeJS:Camera:RecordingManagement");
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
import { Characteristic } from '../Characteristic.js';
|
|
6
|
+
import { DataStreamManagement, HDSConnectionError, HDSProtocolError, HDSStatus, } from '../datastream/index.js';
|
|
7
|
+
import { Service } from '../Service.js';
|
|
8
|
+
import { HapStatusError } from '../util/hapStatusError.js';
|
|
9
|
+
import { decode, encode } from '../util/tlv.js';
|
|
10
|
+
const debug = createDebug('HAP-NodeJS:Camera:RecordingManagement');
|
|
14
11
|
/**
|
|
15
12
|
* Describes the Event trigger.
|
|
16
13
|
*
|
|
17
14
|
* @group Camera
|
|
18
15
|
*/
|
|
19
|
-
|
|
16
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
17
|
+
export var EventTriggerOption;
|
|
20
18
|
(function (EventTriggerOption) {
|
|
21
19
|
/**
|
|
22
20
|
* The Motion trigger. If enabled motion should trigger the start of a recording.
|
|
@@ -31,20 +29,23 @@ var EventTriggerOption;
|
|
|
31
29
|
* See https://github.com/homebridge/HAP-NodeJS/issues/976#issuecomment-1280301989.
|
|
32
30
|
*/
|
|
33
31
|
EventTriggerOption[EventTriggerOption["DOORBELL"] = 2] = "DOORBELL";
|
|
34
|
-
})(EventTriggerOption || (
|
|
32
|
+
})(EventTriggerOption || (EventTriggerOption = {}));
|
|
35
33
|
/**
|
|
36
34
|
* @group Camera
|
|
37
35
|
*/
|
|
38
|
-
|
|
36
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
37
|
+
export var MediaContainerType;
|
|
39
38
|
(function (MediaContainerType) {
|
|
40
39
|
MediaContainerType[MediaContainerType["FRAGMENTED_MP4"] = 0] = "FRAGMENTED_MP4";
|
|
41
|
-
})(MediaContainerType || (
|
|
40
|
+
})(MediaContainerType || (MediaContainerType = {}));
|
|
41
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
42
42
|
var VideoCodecConfigurationTypes;
|
|
43
43
|
(function (VideoCodecConfigurationTypes) {
|
|
44
44
|
VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE";
|
|
45
45
|
VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS";
|
|
46
46
|
VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["ATTRIBUTES"] = 3] = "ATTRIBUTES";
|
|
47
47
|
})(VideoCodecConfigurationTypes || (VideoCodecConfigurationTypes = {}));
|
|
48
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
48
49
|
var VideoCodecParametersTypes;
|
|
49
50
|
(function (VideoCodecParametersTypes) {
|
|
50
51
|
VideoCodecParametersTypes[VideoCodecParametersTypes["PROFILE_ID"] = 1] = "PROFILE_ID";
|
|
@@ -52,12 +53,14 @@ var VideoCodecParametersTypes;
|
|
|
52
53
|
VideoCodecParametersTypes[VideoCodecParametersTypes["BITRATE"] = 3] = "BITRATE";
|
|
53
54
|
VideoCodecParametersTypes[VideoCodecParametersTypes["IFRAME_INTERVAL"] = 4] = "IFRAME_INTERVAL";
|
|
54
55
|
})(VideoCodecParametersTypes || (VideoCodecParametersTypes = {}));
|
|
56
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
55
57
|
var VideoAttributesTypes;
|
|
56
58
|
(function (VideoAttributesTypes) {
|
|
57
59
|
VideoAttributesTypes[VideoAttributesTypes["IMAGE_WIDTH"] = 1] = "IMAGE_WIDTH";
|
|
58
60
|
VideoAttributesTypes[VideoAttributesTypes["IMAGE_HEIGHT"] = 2] = "IMAGE_HEIGHT";
|
|
59
61
|
VideoAttributesTypes[VideoAttributesTypes["FRAME_RATE"] = 3] = "FRAME_RATE";
|
|
60
62
|
})(VideoAttributesTypes || (VideoAttributesTypes = {}));
|
|
63
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
61
64
|
var SelectedCameraRecordingConfigurationTypes;
|
|
62
65
|
(function (SelectedCameraRecordingConfigurationTypes) {
|
|
63
66
|
SelectedCameraRecordingConfigurationTypes[SelectedCameraRecordingConfigurationTypes["SELECTED_RECORDING_CONFIGURATION"] = 1] = "SELECTED_RECORDING_CONFIGURATION";
|
|
@@ -67,15 +70,17 @@ var SelectedCameraRecordingConfigurationTypes;
|
|
|
67
70
|
/**
|
|
68
71
|
* @group Camera
|
|
69
72
|
*/
|
|
70
|
-
|
|
73
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
74
|
+
export var AudioRecordingCodecType;
|
|
71
75
|
(function (AudioRecordingCodecType) {
|
|
72
76
|
AudioRecordingCodecType[AudioRecordingCodecType["AAC_LC"] = 0] = "AAC_LC";
|
|
73
77
|
AudioRecordingCodecType[AudioRecordingCodecType["AAC_ELD"] = 1] = "AAC_ELD";
|
|
74
|
-
})(AudioRecordingCodecType || (
|
|
78
|
+
})(AudioRecordingCodecType || (AudioRecordingCodecType = {}));
|
|
75
79
|
/**
|
|
76
80
|
* @group Camera
|
|
77
81
|
*/
|
|
78
|
-
|
|
82
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
83
|
+
export var AudioRecordingSamplerate;
|
|
79
84
|
(function (AudioRecordingSamplerate) {
|
|
80
85
|
AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_8"] = 0] = "KHZ_8";
|
|
81
86
|
AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_16"] = 1] = "KHZ_16";
|
|
@@ -83,38 +88,45 @@ var AudioRecordingSamplerate;
|
|
|
83
88
|
AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_32"] = 3] = "KHZ_32";
|
|
84
89
|
AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_44_1"] = 4] = "KHZ_44_1";
|
|
85
90
|
AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_48"] = 5] = "KHZ_48";
|
|
86
|
-
})(AudioRecordingSamplerate || (
|
|
91
|
+
})(AudioRecordingSamplerate || (AudioRecordingSamplerate = {}));
|
|
92
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
87
93
|
var SupportedVideoRecordingConfigurationTypes;
|
|
88
94
|
(function (SupportedVideoRecordingConfigurationTypes) {
|
|
89
95
|
SupportedVideoRecordingConfigurationTypes[SupportedVideoRecordingConfigurationTypes["VIDEO_CODEC_CONFIGURATION"] = 1] = "VIDEO_CODEC_CONFIGURATION";
|
|
90
96
|
})(SupportedVideoRecordingConfigurationTypes || (SupportedVideoRecordingConfigurationTypes = {}));
|
|
97
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
91
98
|
var SupportedCameraRecordingConfigurationTypes;
|
|
92
99
|
(function (SupportedCameraRecordingConfigurationTypes) {
|
|
93
100
|
SupportedCameraRecordingConfigurationTypes[SupportedCameraRecordingConfigurationTypes["PREBUFFER_LENGTH"] = 1] = "PREBUFFER_LENGTH";
|
|
94
101
|
SupportedCameraRecordingConfigurationTypes[SupportedCameraRecordingConfigurationTypes["EVENT_TRIGGER_OPTIONS"] = 2] = "EVENT_TRIGGER_OPTIONS";
|
|
95
102
|
SupportedCameraRecordingConfigurationTypes[SupportedCameraRecordingConfigurationTypes["MEDIA_CONTAINER_CONFIGURATIONS"] = 3] = "MEDIA_CONTAINER_CONFIGURATIONS";
|
|
96
103
|
})(SupportedCameraRecordingConfigurationTypes || (SupportedCameraRecordingConfigurationTypes = {}));
|
|
104
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
97
105
|
var MediaContainerConfigurationTypes;
|
|
98
106
|
(function (MediaContainerConfigurationTypes) {
|
|
99
107
|
MediaContainerConfigurationTypes[MediaContainerConfigurationTypes["MEDIA_CONTAINER_TYPE"] = 1] = "MEDIA_CONTAINER_TYPE";
|
|
100
108
|
MediaContainerConfigurationTypes[MediaContainerConfigurationTypes["MEDIA_CONTAINER_PARAMETERS"] = 2] = "MEDIA_CONTAINER_PARAMETERS";
|
|
101
109
|
})(MediaContainerConfigurationTypes || (MediaContainerConfigurationTypes = {}));
|
|
110
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
102
111
|
var MediaContainerParameterTypes;
|
|
103
112
|
(function (MediaContainerParameterTypes) {
|
|
104
113
|
MediaContainerParameterTypes[MediaContainerParameterTypes["FRAGMENT_LENGTH"] = 1] = "FRAGMENT_LENGTH";
|
|
105
114
|
})(MediaContainerParameterTypes || (MediaContainerParameterTypes = {}));
|
|
115
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
106
116
|
var AudioCodecParametersTypes;
|
|
107
117
|
(function (AudioCodecParametersTypes) {
|
|
108
118
|
AudioCodecParametersTypes[AudioCodecParametersTypes["CHANNEL"] = 1] = "CHANNEL";
|
|
109
119
|
AudioCodecParametersTypes[AudioCodecParametersTypes["BIT_RATE"] = 2] = "BIT_RATE";
|
|
110
120
|
AudioCodecParametersTypes[AudioCodecParametersTypes["SAMPLE_RATE"] = 3] = "SAMPLE_RATE";
|
|
111
|
-
AudioCodecParametersTypes[AudioCodecParametersTypes["MAX_AUDIO_BITRATE"] = 4] = "MAX_AUDIO_BITRATE";
|
|
121
|
+
AudioCodecParametersTypes[AudioCodecParametersTypes["MAX_AUDIO_BITRATE"] = 4] = "MAX_AUDIO_BITRATE";
|
|
112
122
|
})(AudioCodecParametersTypes || (AudioCodecParametersTypes = {}));
|
|
123
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
113
124
|
var AudioCodecConfigurationTypes;
|
|
114
125
|
(function (AudioCodecConfigurationTypes) {
|
|
115
126
|
AudioCodecConfigurationTypes[AudioCodecConfigurationTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE";
|
|
116
127
|
AudioCodecConfigurationTypes[AudioCodecConfigurationTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS";
|
|
117
128
|
})(AudioCodecConfigurationTypes || (AudioCodecConfigurationTypes = {}));
|
|
129
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
118
130
|
var SupportedAudioRecordingConfigurationTypes;
|
|
119
131
|
(function (SupportedAudioRecordingConfigurationTypes) {
|
|
120
132
|
SupportedAudioRecordingConfigurationTypes[SupportedAudioRecordingConfigurationTypes["AUDIO_CODEC_CONFIGURATION"] = 1] = "AUDIO_CODEC_CONFIGURATION";
|
|
@@ -122,7 +134,8 @@ var SupportedAudioRecordingConfigurationTypes;
|
|
|
122
134
|
/**
|
|
123
135
|
* @group Camera
|
|
124
136
|
*/
|
|
125
|
-
|
|
137
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
138
|
+
export var PacketDataType;
|
|
126
139
|
(function (PacketDataType) {
|
|
127
140
|
/**
|
|
128
141
|
* mp4 moov box
|
|
@@ -132,11 +145,11 @@ var PacketDataType;
|
|
|
132
145
|
* mp4 moof + mdat boxes
|
|
133
146
|
*/
|
|
134
147
|
PacketDataType["MEDIA_FRAGMENT"] = "mediaFragment";
|
|
135
|
-
})(PacketDataType || (
|
|
148
|
+
})(PacketDataType || (PacketDataType = {}));
|
|
136
149
|
/**
|
|
137
150
|
* @group Camera
|
|
138
151
|
*/
|
|
139
|
-
class RecordingManagement {
|
|
152
|
+
export class RecordingManagement {
|
|
140
153
|
options;
|
|
141
154
|
delegate;
|
|
142
155
|
stateChangeDelegate;
|
|
@@ -184,32 +197,32 @@ class RecordingManagement {
|
|
|
184
197
|
this.setupServiceHandlers();
|
|
185
198
|
}
|
|
186
199
|
constructService() {
|
|
187
|
-
const recordingManagement = new
|
|
188
|
-
recordingManagement.setCharacteristic(
|
|
189
|
-
recordingManagement.setCharacteristic(
|
|
190
|
-
const operatingMode = new
|
|
191
|
-
operatingMode.setCharacteristic(
|
|
192
|
-
operatingMode.setCharacteristic(
|
|
193
|
-
operatingMode.setCharacteristic(
|
|
194
|
-
const dataStreamManagement = new
|
|
200
|
+
const recordingManagement = new Service.CameraRecordingManagement('', '');
|
|
201
|
+
recordingManagement.setCharacteristic(Characteristic.Active, false);
|
|
202
|
+
recordingManagement.setCharacteristic(Characteristic.RecordingAudioActive, false);
|
|
203
|
+
const operatingMode = new Service.CameraOperatingMode('', '');
|
|
204
|
+
operatingMode.setCharacteristic(Characteristic.EventSnapshotsActive, true);
|
|
205
|
+
operatingMode.setCharacteristic(Characteristic.HomeKitCameraActive, true);
|
|
206
|
+
operatingMode.setCharacteristic(Characteristic.PeriodicSnapshotsActive, true);
|
|
207
|
+
const dataStreamManagement = new DataStreamManagement();
|
|
195
208
|
recordingManagement.addLinkedService(dataStreamManagement.getService());
|
|
196
209
|
return {
|
|
197
|
-
recordingManagement
|
|
198
|
-
operatingMode
|
|
199
|
-
dataStreamManagement
|
|
210
|
+
recordingManagement,
|
|
211
|
+
operatingMode,
|
|
212
|
+
dataStreamManagement,
|
|
200
213
|
};
|
|
201
214
|
}
|
|
202
215
|
setupServiceHandlers() {
|
|
203
216
|
// update the current configuration values to the current state.
|
|
204
|
-
this.recordingManagementService.setCharacteristic(
|
|
205
|
-
this.recordingManagementService.setCharacteristic(
|
|
206
|
-
this.recordingManagementService.setCharacteristic(
|
|
207
|
-
this.recordingManagementService.getCharacteristic(
|
|
217
|
+
this.recordingManagementService.setCharacteristic(Characteristic.SupportedCameraRecordingConfiguration, this.supportedCameraRecordingConfiguration);
|
|
218
|
+
this.recordingManagementService.setCharacteristic(Characteristic.SupportedVideoRecordingConfiguration, this.supportedVideoRecordingConfiguration);
|
|
219
|
+
this.recordingManagementService.setCharacteristic(Characteristic.SupportedAudioRecordingConfiguration, this.supportedAudioRecordingConfiguration);
|
|
220
|
+
this.recordingManagementService.getCharacteristic(Characteristic.SelectedCameraRecordingConfiguration)
|
|
208
221
|
.onGet(this.handleSelectedCameraRecordingConfigurationRead.bind(this))
|
|
209
222
|
.onSet(this.handleSelectedCameraRecordingConfigurationWrite.bind(this))
|
|
210
223
|
.setProps({ adminOnlyAccess: [1 /* Access.WRITE */] });
|
|
211
|
-
this.recordingManagementService.getCharacteristic(
|
|
212
|
-
.onSet(value => {
|
|
224
|
+
this.recordingManagementService.getCharacteristic(Characteristic.Active)
|
|
225
|
+
.onSet((value) => {
|
|
213
226
|
if (!!value === this.recordingActive) {
|
|
214
227
|
return; // skip delegate call if state didn't change!
|
|
215
228
|
}
|
|
@@ -218,12 +231,12 @@ class RecordingManagement {
|
|
|
218
231
|
})
|
|
219
232
|
.on("change" /* CharacteristicEventTypes.CHANGE */, () => this.stateChangeDelegate?.())
|
|
220
233
|
.setProps({ adminOnlyAccess: [1 /* Access.WRITE */] });
|
|
221
|
-
this.recordingManagementService.getCharacteristic(
|
|
234
|
+
this.recordingManagementService.getCharacteristic(Characteristic.RecordingAudioActive)
|
|
222
235
|
.on("change" /* CharacteristicEventTypes.CHANGE */, () => this.stateChangeDelegate?.());
|
|
223
|
-
this.operatingModeService.getCharacteristic(
|
|
224
|
-
.on("change" /* CharacteristicEventTypes.CHANGE */, change => {
|
|
236
|
+
this.operatingModeService.getCharacteristic(Characteristic.HomeKitCameraActive)
|
|
237
|
+
.on("change" /* CharacteristicEventTypes.CHANGE */, (change) => {
|
|
225
238
|
for (const service of this.sensorServices) {
|
|
226
|
-
service.setCharacteristic(
|
|
239
|
+
service.setCharacteristic(Characteristic.StatusActive, !!change.newValue);
|
|
227
240
|
}
|
|
228
241
|
if (!change.newValue && this.recordingStream) {
|
|
229
242
|
this.recordingStream.close(1 /* HDSProtocolSpecificErrorReason.NOT_ALLOWED */);
|
|
@@ -231,71 +244,70 @@ class RecordingManagement {
|
|
|
231
244
|
this.stateChangeDelegate?.();
|
|
232
245
|
})
|
|
233
246
|
.setProps({ adminOnlyAccess: [1 /* Access.WRITE */] });
|
|
234
|
-
this.operatingModeService.getCharacteristic(
|
|
247
|
+
this.operatingModeService.getCharacteristic(Characteristic.EventSnapshotsActive)
|
|
235
248
|
.on("change" /* CharacteristicEventTypes.CHANGE */, () => this.stateChangeDelegate?.())
|
|
236
249
|
.setProps({ adminOnlyAccess: [1 /* Access.WRITE */] });
|
|
237
|
-
this.operatingModeService.getCharacteristic(
|
|
250
|
+
this.operatingModeService.getCharacteristic(Characteristic.PeriodicSnapshotsActive)
|
|
238
251
|
.on("change" /* CharacteristicEventTypes.CHANGE */, () => this.stateChangeDelegate?.())
|
|
239
252
|
.setProps({ adminOnlyAccess: [1 /* Access.WRITE */] });
|
|
240
253
|
this.dataStreamManagement
|
|
241
254
|
.onRequestMessage("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, this.handleDataSendOpen.bind(this));
|
|
242
255
|
}
|
|
243
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
256
|
handleDataSendOpen(connection, id, message) {
|
|
245
257
|
// for message fields see https://github.com/Supereg/secure-video-specification#41-start
|
|
246
258
|
const streamId = message.streamId;
|
|
247
259
|
const type = message.type;
|
|
248
260
|
const target = message.target;
|
|
249
261
|
const reason = message.reason;
|
|
250
|
-
if (target !==
|
|
251
|
-
debug(
|
|
252
|
-
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id,
|
|
262
|
+
if (target !== 'controller' || type !== 'ipcamera.recording') {
|
|
263
|
+
debug('[HDS %s] Received data send with unexpected target: %s or type: %d. Rejecting...', connection.remoteAddress, target, type);
|
|
264
|
+
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id, HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
|
|
253
265
|
status: 5 /* HDSProtocolSpecificErrorReason.UNEXPECTED_FAILURE */,
|
|
254
266
|
});
|
|
255
267
|
return;
|
|
256
268
|
}
|
|
257
269
|
if (!this.recordingActive) {
|
|
258
|
-
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id,
|
|
270
|
+
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id, HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
|
|
259
271
|
status: 1 /* HDSProtocolSpecificErrorReason.NOT_ALLOWED */,
|
|
260
272
|
});
|
|
261
273
|
return;
|
|
262
274
|
}
|
|
263
|
-
if (!this.operatingModeService.getCharacteristic(
|
|
264
|
-
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id,
|
|
275
|
+
if (!this.operatingModeService.getCharacteristic(Characteristic.HomeKitCameraActive).value) {
|
|
276
|
+
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id, HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
|
|
265
277
|
status: 1 /* HDSProtocolSpecificErrorReason.NOT_ALLOWED */,
|
|
266
278
|
});
|
|
267
279
|
return;
|
|
268
280
|
}
|
|
269
281
|
if (this.recordingStream) {
|
|
270
|
-
debug(
|
|
282
|
+
debug('[HDS %s] Rejecting DATA_SEND OPEN as another stream (%s) is already recording with streamId %d!', connection.remoteAddress, this.recordingStream.connection.remoteAddress, this.recordingStream.streamId);
|
|
271
283
|
// there is already a recording stream running.
|
|
272
|
-
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id,
|
|
284
|
+
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id, HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
|
|
273
285
|
status: 2 /* HDSProtocolSpecificErrorReason.BUSY */,
|
|
274
286
|
});
|
|
275
287
|
return;
|
|
276
288
|
}
|
|
277
289
|
if (!this.selectedConfiguration) {
|
|
278
|
-
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id,
|
|
290
|
+
connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, id, HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
|
|
279
291
|
status: 9 /* HDSProtocolSpecificErrorReason.INVALID_CONFIGURATION */,
|
|
280
292
|
});
|
|
281
293
|
return;
|
|
282
294
|
}
|
|
283
|
-
debug(
|
|
284
|
-
// eslint-disable-next-line
|
|
295
|
+
debug('[HDS %s] HDS DATA_SEND Open with reason \'%s\'.', connection.remoteAddress, reason);
|
|
296
|
+
// eslint-disable-next-line ts/no-use-before-define
|
|
285
297
|
this.recordingStream = new CameraRecordingStream(connection, this.delegate, id, streamId);
|
|
298
|
+
// eslint-disable-next-line ts/no-use-before-define
|
|
286
299
|
this.recordingStream.on("closed" /* CameraRecordingStreamEvents.CLOSED */, () => {
|
|
287
|
-
debug(
|
|
300
|
+
debug('[HDS %s] Removing active recoding session from recording management!', connection.remoteAddress);
|
|
288
301
|
this.recordingStream = undefined;
|
|
289
302
|
});
|
|
290
303
|
this.recordingStream.startStreaming();
|
|
291
304
|
}
|
|
292
305
|
handleSelectedCameraRecordingConfigurationRead() {
|
|
293
306
|
if (!this.selectedConfiguration) {
|
|
294
|
-
throw new
|
|
307
|
+
throw new HapStatusError(-70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
|
|
295
308
|
}
|
|
296
309
|
return this.selectedConfiguration.base64;
|
|
297
310
|
}
|
|
298
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
299
311
|
handleSelectedCameraRecordingConfigurationWrite(value) {
|
|
300
312
|
const configuration = this.parseSelectedConfiguration(value);
|
|
301
313
|
const changed = this.selectedConfiguration?.base64 !== value;
|
|
@@ -310,19 +322,19 @@ class RecordingManagement {
|
|
|
310
322
|
}
|
|
311
323
|
}
|
|
312
324
|
parseSelectedConfiguration(value) {
|
|
313
|
-
const decoded =
|
|
314
|
-
const recording =
|
|
315
|
-
const video =
|
|
316
|
-
const audio =
|
|
325
|
+
const decoded = decode(Buffer.from(value, 'base64'));
|
|
326
|
+
const recording = decode(decoded[1 /* SelectedCameraRecordingConfigurationTypes.SELECTED_RECORDING_CONFIGURATION */]);
|
|
327
|
+
const video = decode(decoded[2 /* SelectedCameraRecordingConfigurationTypes.SELECTED_VIDEO_CONFIGURATION */]);
|
|
328
|
+
const audio = decode(decoded[3 /* SelectedCameraRecordingConfigurationTypes.SELECTED_AUDIO_CONFIGURATION */]);
|
|
317
329
|
const prebufferLength = recording[1 /* SupportedCameraRecordingConfigurationTypes.PREBUFFER_LENGTH */].readInt32LE(0);
|
|
318
330
|
let eventTriggerOptions = recording[2 /* SupportedCameraRecordingConfigurationTypes.EVENT_TRIGGER_OPTIONS */].readInt32LE(0);
|
|
319
|
-
const mediaContainerConfiguration =
|
|
331
|
+
const mediaContainerConfiguration = decode(recording[3 /* SupportedCameraRecordingConfigurationTypes.MEDIA_CONTAINER_CONFIGURATIONS */]);
|
|
320
332
|
const containerType = mediaContainerConfiguration[1 /* MediaContainerConfigurationTypes.MEDIA_CONTAINER_TYPE */][0];
|
|
321
|
-
const mediaContainerParameters =
|
|
333
|
+
const mediaContainerParameters = decode(mediaContainerConfiguration[2 /* MediaContainerConfigurationTypes.MEDIA_CONTAINER_PARAMETERS */]);
|
|
322
334
|
const fragmentLength = mediaContainerParameters[1 /* MediaContainerParameterTypes.FRAGMENT_LENGTH */].readInt32LE(0);
|
|
323
335
|
const videoCodec = video[1 /* VideoCodecConfigurationTypes.CODEC_TYPE */][0];
|
|
324
|
-
const videoParameters =
|
|
325
|
-
const videoAttributes =
|
|
336
|
+
const videoParameters = decode(video[2 /* VideoCodecConfigurationTypes.CODEC_PARAMETERS */]);
|
|
337
|
+
const videoAttributes = decode(video[3 /* VideoCodecConfigurationTypes.ATTRIBUTES */]);
|
|
326
338
|
const profile = videoParameters[1 /* VideoCodecParametersTypes.PROFILE_ID */][0];
|
|
327
339
|
const level = videoParameters[2 /* VideoCodecParametersTypes.LEVEL */][0];
|
|
328
340
|
const videoBitrate = videoParameters[3 /* VideoCodecParametersTypes.BITRATE */].readInt32LE(0);
|
|
@@ -331,22 +343,22 @@ class RecordingManagement {
|
|
|
331
343
|
const height = videoAttributes[2 /* VideoAttributesTypes.IMAGE_HEIGHT */].readInt16LE(0);
|
|
332
344
|
const framerate = videoAttributes[3 /* VideoAttributesTypes.FRAME_RATE */][0];
|
|
333
345
|
const audioCodec = audio[1 /* AudioCodecConfigurationTypes.CODEC_TYPE */][0];
|
|
334
|
-
const audioParameters =
|
|
346
|
+
const audioParameters = decode(audio[2 /* AudioCodecConfigurationTypes.CODEC_PARAMETERS */]);
|
|
335
347
|
const audioChannels = audioParameters[1 /* AudioCodecParametersTypes.CHANNEL */][0];
|
|
336
348
|
const samplerate = audioParameters[3 /* AudioCodecParametersTypes.SAMPLE_RATE */][0];
|
|
337
349
|
const audioBitrateMode = audioParameters[2 /* AudioCodecParametersTypes.BIT_RATE */][0];
|
|
338
350
|
const audioBitrate = audioParameters[4 /* AudioCodecParametersTypes.MAX_AUDIO_BITRATE */].readUInt32LE(0);
|
|
339
351
|
const typedEventTriggers = [];
|
|
340
|
-
let
|
|
352
|
+
let bitIndex = 0;
|
|
341
353
|
while (eventTriggerOptions > 0) {
|
|
342
|
-
if (eventTriggerOptions
|
|
343
|
-
typedEventTriggers.push(1 <<
|
|
354
|
+
if (eventTriggerOptions % 2 === 1) { // check if the lowest bit is set
|
|
355
|
+
typedEventTriggers.push(1 << bitIndex);
|
|
344
356
|
}
|
|
345
|
-
eventTriggerOptions = eventTriggerOptions
|
|
346
|
-
|
|
357
|
+
eventTriggerOptions = Math.floor(eventTriggerOptions / 2); // shift right by dividing by 2
|
|
358
|
+
bitIndex += 1;
|
|
347
359
|
}
|
|
348
360
|
return {
|
|
349
|
-
prebufferLength
|
|
361
|
+
prebufferLength,
|
|
350
362
|
eventTriggerTypes: typedEventTriggers,
|
|
351
363
|
mediaContainerConfiguration: {
|
|
352
364
|
type: containerType,
|
|
@@ -355,10 +367,10 @@ class RecordingManagement {
|
|
|
355
367
|
videoCodec: {
|
|
356
368
|
type: videoCodec,
|
|
357
369
|
parameters: {
|
|
358
|
-
profile
|
|
359
|
-
level
|
|
370
|
+
profile,
|
|
371
|
+
level,
|
|
360
372
|
bitRate: videoBitrate,
|
|
361
|
-
iFrameInterval
|
|
373
|
+
iFrameInterval,
|
|
362
374
|
},
|
|
363
375
|
resolution: [width, height, framerate],
|
|
364
376
|
},
|
|
@@ -379,23 +391,23 @@ class RecordingManagement {
|
|
|
379
391
|
const eventTriggerOptions = Buffer.alloc(8);
|
|
380
392
|
prebufferLength.writeInt32LE(options.prebufferLength, 0);
|
|
381
393
|
eventTriggerOptions.writeInt32LE(this.eventTriggerOptions, 0);
|
|
382
|
-
return
|
|
394
|
+
return encode(1 /* SupportedCameraRecordingConfigurationTypes.PREBUFFER_LENGTH */, prebufferLength, 2 /* SupportedCameraRecordingConfigurationTypes.EVENT_TRIGGER_OPTIONS */, eventTriggerOptions, 3 /* SupportedCameraRecordingConfigurationTypes.MEDIA_CONTAINER_CONFIGURATIONS */, mediaContainers.map((config) => {
|
|
383
395
|
const fragmentLength = Buffer.alloc(4);
|
|
384
396
|
fragmentLength.writeInt32LE(config.fragmentLength, 0);
|
|
385
|
-
return
|
|
386
|
-
})).toString(
|
|
397
|
+
return encode(1 /* MediaContainerConfigurationTypes.MEDIA_CONTAINER_TYPE */, config.type, 2 /* MediaContainerConfigurationTypes.MEDIA_CONTAINER_PARAMETERS */, encode(1 /* MediaContainerParameterTypes.FRAGMENT_LENGTH */, fragmentLength));
|
|
398
|
+
})).toString('base64');
|
|
387
399
|
}
|
|
388
400
|
_supportedVideoRecordingConfiguration(videoOptions) {
|
|
389
401
|
if (!videoOptions.parameters) {
|
|
390
|
-
throw new Error(
|
|
402
|
+
throw new Error('Video parameters cannot be undefined');
|
|
391
403
|
}
|
|
392
404
|
if (!videoOptions.resolutions) {
|
|
393
|
-
throw new Error(
|
|
405
|
+
throw new Error('Video resolutions cannot be undefined');
|
|
394
406
|
}
|
|
395
|
-
const codecParameters =
|
|
396
|
-
const videoStreamConfiguration =
|
|
407
|
+
const codecParameters = encode(1 /* VideoCodecParametersTypes.PROFILE_ID */, videoOptions.parameters.profiles, 2 /* VideoCodecParametersTypes.LEVEL */, videoOptions.parameters.levels);
|
|
408
|
+
const videoStreamConfiguration = encode(1 /* VideoCodecConfigurationTypes.CODEC_TYPE */, videoOptions.type, 2 /* VideoCodecConfigurationTypes.CODEC_PARAMETERS */, codecParameters, 3 /* VideoCodecConfigurationTypes.ATTRIBUTES */, videoOptions.resolutions.map((resolution) => {
|
|
397
409
|
if (resolution.length !== 3) {
|
|
398
|
-
throw new Error(
|
|
410
|
+
throw new Error('Unexpected video resolution');
|
|
399
411
|
}
|
|
400
412
|
const width = Buffer.alloc(2);
|
|
401
413
|
const height = Buffer.alloc(2);
|
|
@@ -403,35 +415,35 @@ class RecordingManagement {
|
|
|
403
415
|
width.writeUInt16LE(resolution[0], 0);
|
|
404
416
|
height.writeUInt16LE(resolution[1], 0);
|
|
405
417
|
frameRate.writeUInt8(resolution[2], 0);
|
|
406
|
-
return
|
|
418
|
+
return encode(1 /* VideoAttributesTypes.IMAGE_WIDTH */, width, 2 /* VideoAttributesTypes.IMAGE_HEIGHT */, height, 3 /* VideoAttributesTypes.FRAME_RATE */, frameRate);
|
|
407
419
|
}));
|
|
408
|
-
return
|
|
420
|
+
return encode(1 /* SupportedVideoRecordingConfigurationTypes.VIDEO_CODEC_CONFIGURATION */, videoStreamConfiguration).toString('base64');
|
|
409
421
|
}
|
|
410
422
|
_supportedAudioStreamConfiguration(audioOptions) {
|
|
411
423
|
const audioCodecs = Array.isArray(audioOptions.codecs)
|
|
412
424
|
? audioOptions.codecs
|
|
413
425
|
: [audioOptions.codecs];
|
|
414
426
|
if (audioCodecs.length === 0) {
|
|
415
|
-
throw Error(
|
|
427
|
+
throw new Error('CameraRecordingOptions.audio: At least one audio codec configuration must be specified!');
|
|
416
428
|
}
|
|
417
|
-
const codecConfigurations = audioCodecs.map(codec => {
|
|
429
|
+
const codecConfigurations = audioCodecs.map((codec) => {
|
|
418
430
|
const providedSamplerates = Array.isArray(codec.samplerate)
|
|
419
431
|
? codec.samplerate
|
|
420
432
|
: [codec.samplerate];
|
|
421
433
|
if (providedSamplerates.length === 0) {
|
|
422
|
-
throw new Error(
|
|
434
|
+
throw new Error('CameraRecordingOptions.audio.codecs: Audio samplerate cannot be empty!');
|
|
423
435
|
}
|
|
424
|
-
const audioParameters =
|
|
425
|
-
return
|
|
436
|
+
const audioParameters = encode(1 /* AudioCodecParametersTypes.CHANNEL */, Math.max(1, codec.audioChannels || 1), 2 /* AudioCodecParametersTypes.BIT_RATE */, codec.bitrateMode || 0 /* AudioBitrate.VARIABLE */, 3 /* AudioCodecParametersTypes.SAMPLE_RATE */, providedSamplerates);
|
|
437
|
+
return encode(1 /* AudioCodecConfigurationTypes.CODEC_TYPE */, codec.type, 2 /* AudioCodecConfigurationTypes.CODEC_PARAMETERS */, audioParameters);
|
|
426
438
|
});
|
|
427
|
-
return
|
|
439
|
+
return encode(1 /* SupportedAudioRecordingConfigurationTypes.AUDIO_CODEC_CONFIGURATION */, codecConfigurations).toString('base64');
|
|
428
440
|
}
|
|
429
|
-
computeConfigurationHash(algorithm =
|
|
430
|
-
const configurationHash =
|
|
441
|
+
computeConfigurationHash(algorithm = 'sha256') {
|
|
442
|
+
const configurationHash = createHash(algorithm);
|
|
431
443
|
configurationHash.update(this.supportedCameraRecordingConfiguration);
|
|
432
444
|
configurationHash.update(this.supportedVideoRecordingConfiguration);
|
|
433
445
|
configurationHash.update(this.supportedAudioRecordingConfiguration);
|
|
434
|
-
return configurationHash.digest().toString(
|
|
446
|
+
return configurationHash.digest().toString('hex');
|
|
435
447
|
}
|
|
436
448
|
/**
|
|
437
449
|
* @private
|
|
@@ -439,15 +451,15 @@ class RecordingManagement {
|
|
|
439
451
|
serialize() {
|
|
440
452
|
return {
|
|
441
453
|
configurationHash: {
|
|
442
|
-
algorithm:
|
|
443
|
-
hash: this.computeConfigurationHash(
|
|
454
|
+
algorithm: 'sha256',
|
|
455
|
+
hash: this.computeConfigurationHash('sha256'),
|
|
444
456
|
},
|
|
445
457
|
selectedConfiguration: this.selectedConfiguration?.base64,
|
|
446
458
|
recordingActive: this.recordingActive,
|
|
447
|
-
recordingAudioActive: !!this.recordingManagementService.getCharacteristic(
|
|
448
|
-
eventSnapshotsActive: !!this.operatingModeService.getCharacteristic(
|
|
449
|
-
homeKitCameraActive: !!this.operatingModeService.getCharacteristic(
|
|
450
|
-
periodicSnapshotsActive: !!this.operatingModeService.getCharacteristic(
|
|
459
|
+
recordingAudioActive: !!this.recordingManagementService.getCharacteristic(Characteristic.RecordingAudioActive).value,
|
|
460
|
+
eventSnapshotsActive: !!this.operatingModeService.getCharacteristic(Characteristic.EventSnapshotsActive).value,
|
|
461
|
+
homeKitCameraActive: !!this.operatingModeService.getCharacteristic(Characteristic.HomeKitCameraActive).value,
|
|
462
|
+
periodicSnapshotsActive: !!this.operatingModeService.getCharacteristic(Characteristic.PeriodicSnapshotsActive).value,
|
|
451
463
|
};
|
|
452
464
|
}
|
|
453
465
|
/**
|
|
@@ -469,13 +481,13 @@ class RecordingManagement {
|
|
|
469
481
|
}
|
|
470
482
|
}
|
|
471
483
|
this.recordingActive = serialized.recordingActive;
|
|
472
|
-
this.recordingManagementService.updateCharacteristic(
|
|
473
|
-
this.recordingManagementService.updateCharacteristic(
|
|
474
|
-
this.operatingModeService.updateCharacteristic(
|
|
475
|
-
this.operatingModeService.updateCharacteristic(
|
|
476
|
-
this.operatingModeService.updateCharacteristic(
|
|
484
|
+
this.recordingManagementService.updateCharacteristic(Characteristic.Active, serialized.recordingActive);
|
|
485
|
+
this.recordingManagementService.updateCharacteristic(Characteristic.RecordingAudioActive, serialized.recordingAudioActive);
|
|
486
|
+
this.operatingModeService.updateCharacteristic(Characteristic.EventSnapshotsActive, serialized.eventSnapshotsActive);
|
|
487
|
+
this.operatingModeService.updateCharacteristic(Characteristic.PeriodicSnapshotsActive, serialized.periodicSnapshotsActive);
|
|
488
|
+
this.operatingModeService.updateCharacteristic(Characteristic.HomeKitCameraActive, serialized.homeKitCameraActive);
|
|
477
489
|
for (const service of this.sensorServices) {
|
|
478
|
-
service.setCharacteristic(
|
|
490
|
+
service.setCharacteristic(Characteristic.StatusActive, serialized.homeKitCameraActive);
|
|
479
491
|
}
|
|
480
492
|
try {
|
|
481
493
|
if (this.selectedConfiguration) {
|
|
@@ -486,7 +498,7 @@ class RecordingManagement {
|
|
|
486
498
|
}
|
|
487
499
|
}
|
|
488
500
|
catch (error) {
|
|
489
|
-
console.error(
|
|
501
|
+
console.error(`Failed to properly initialize CameraRecordingDelegate from persistent storage: ${error.stack}`);
|
|
490
502
|
}
|
|
491
503
|
if (changedState) {
|
|
492
504
|
this.stateChangeDelegate?.();
|
|
@@ -503,13 +515,13 @@ class RecordingManagement {
|
|
|
503
515
|
}
|
|
504
516
|
handleFactoryReset() {
|
|
505
517
|
this.selectedConfiguration = undefined;
|
|
506
|
-
this.recordingManagementService.updateCharacteristic(
|
|
507
|
-
this.recordingManagementService.updateCharacteristic(
|
|
508
|
-
this.operatingModeService.updateCharacteristic(
|
|
509
|
-
this.operatingModeService.updateCharacteristic(
|
|
510
|
-
this.operatingModeService.updateCharacteristic(
|
|
518
|
+
this.recordingManagementService.updateCharacteristic(Characteristic.Active, false);
|
|
519
|
+
this.recordingManagementService.updateCharacteristic(Characteristic.RecordingAudioActive, false);
|
|
520
|
+
this.operatingModeService.updateCharacteristic(Characteristic.EventSnapshotsActive, true);
|
|
521
|
+
this.operatingModeService.updateCharacteristic(Characteristic.PeriodicSnapshotsActive, true);
|
|
522
|
+
this.operatingModeService.updateCharacteristic(Characteristic.HomeKitCameraActive, true);
|
|
511
523
|
for (const service of this.sensorServices) {
|
|
512
|
-
service.setCharacteristic(
|
|
524
|
+
service.setCharacteristic(Characteristic.StatusActive, true);
|
|
513
525
|
}
|
|
514
526
|
try {
|
|
515
527
|
// notifying the delegate about the updated state
|
|
@@ -517,14 +529,14 @@ class RecordingManagement {
|
|
|
517
529
|
this.delegate.updateRecordingConfiguration(undefined);
|
|
518
530
|
}
|
|
519
531
|
catch (error) {
|
|
520
|
-
console.error(
|
|
532
|
+
console.error(`CameraRecordingDelegate failed to update state after handleFactoryReset: ${error.stack}`);
|
|
521
533
|
}
|
|
522
534
|
}
|
|
523
535
|
}
|
|
524
|
-
exports.RecordingManagement = RecordingManagement;
|
|
525
536
|
/**
|
|
526
537
|
* @group Camera
|
|
527
538
|
*/
|
|
539
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
528
540
|
var CameraRecordingStreamEvents;
|
|
529
541
|
(function (CameraRecordingStreamEvents) {
|
|
530
542
|
/**
|
|
@@ -540,8 +552,8 @@ var CameraRecordingStreamEvents;
|
|
|
540
552
|
*
|
|
541
553
|
* @group Camera
|
|
542
554
|
*/
|
|
543
|
-
// eslint-disable-next-line
|
|
544
|
-
class CameraRecordingStream extends
|
|
555
|
+
// eslint-disable-next-line ts/no-unsafe-declaration-merging
|
|
556
|
+
class CameraRecordingStream extends EventEmitter {
|
|
545
557
|
connection;
|
|
546
558
|
delegate;
|
|
547
559
|
hdsRequestId;
|
|
@@ -575,13 +587,12 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
575
587
|
this.connection.addProtocolHandler("dataSend" /* Protocols.DATA_SEND */, this);
|
|
576
588
|
}
|
|
577
589
|
startStreaming() {
|
|
578
|
-
// noinspection JSIgnoredPromiseFromCall
|
|
579
590
|
this._startStreaming();
|
|
580
591
|
}
|
|
581
592
|
async _startStreaming() {
|
|
582
|
-
debug(
|
|
583
|
-
this.connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, this.hdsRequestId,
|
|
584
|
-
status:
|
|
593
|
+
debug('[HDS %s] Sending DATA_SEND OPEN response for streamId %d', this.connection.remoteAddress, this.streamId);
|
|
594
|
+
this.connection.sendResponse("dataSend" /* Protocols.DATA_SEND */, "open" /* Topics.OPEN */, this.hdsRequestId, HDSStatus.SUCCESS, {
|
|
595
|
+
status: HDSStatus.SUCCESS,
|
|
585
596
|
});
|
|
586
597
|
// 256 KiB (1KiB to 900 KiB)
|
|
587
598
|
const maxChunk = 0x40000;
|
|
@@ -608,24 +619,24 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
608
619
|
if (this.closed) {
|
|
609
620
|
break;
|
|
610
621
|
}
|
|
611
|
-
const data = fragment.
|
|
622
|
+
const data = fragment.subarray(offset, offset + maxChunk);
|
|
612
623
|
offset += data.length;
|
|
613
624
|
// see https://github.com/Supereg/secure-video-specification#42-binary-data
|
|
614
625
|
const event = {
|
|
615
626
|
streamId: this.streamId,
|
|
616
627
|
packets: [{
|
|
617
|
-
data
|
|
628
|
+
data,
|
|
618
629
|
metadata: {
|
|
619
630
|
dataType: initialization ? "mediaInitialization" /* PacketDataType.MEDIA_INITIALIZATION */ : "mediaFragment" /* PacketDataType.MEDIA_FRAGMENT */,
|
|
620
|
-
dataSequenceNumber
|
|
621
|
-
dataChunkSequenceNumber
|
|
631
|
+
dataSequenceNumber,
|
|
632
|
+
dataChunkSequenceNumber,
|
|
622
633
|
isLastDataChunk: offset >= fragment.length,
|
|
623
634
|
dataTotalSize: dataChunkSequenceNumber === 1 ? fragment.length : undefined,
|
|
624
635
|
},
|
|
625
636
|
}],
|
|
626
637
|
endOfStream: offset >= fragment.length ? Boolean(packet.isLast).valueOf() : undefined,
|
|
627
638
|
};
|
|
628
|
-
debug(
|
|
639
|
+
debug('[HDS %s] Sending DATA_SEND DATA for stream %d with metadata: %o and length %d; EoS: %s', this.connection.remoteAddress, this.streamId, event.packets[0].metadata, data.length, event.endOfStream);
|
|
629
640
|
this.connection.sendEvent("dataSend" /* Protocols.DATA_SEND */, "data" /* Topics.DATA */, event);
|
|
630
641
|
dataChunkSequenceNumber++;
|
|
631
642
|
initialization = false;
|
|
@@ -638,8 +649,8 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
638
649
|
}
|
|
639
650
|
if (!lastFragmentWasMarkedLast && !this.closed) {
|
|
640
651
|
// Delegate violates the contract. Exited normally on a non-closed stream without properly setting `isLast`.
|
|
641
|
-
console.warn(`[HDS ${this.connection.remoteAddress}] Delegate finished streaming for ${this.streamId} without setting RecordingPacket.isLast. `
|
|
642
|
-
|
|
652
|
+
console.warn(`[HDS ${this.connection.remoteAddress}] Delegate finished streaming for ${this.streamId} without setting RecordingPacket.isLast. `
|
|
653
|
+
+ 'Can\'t notify Controller about endOfStream!');
|
|
643
654
|
}
|
|
644
655
|
}
|
|
645
656
|
catch (error) {
|
|
@@ -648,13 +659,13 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
648
659
|
}
|
|
649
660
|
else {
|
|
650
661
|
let closeReason = 5 /* HDSProtocolSpecificErrorReason.UNEXPECTED_FAILURE */;
|
|
651
|
-
if (error instanceof
|
|
662
|
+
if (error instanceof HDSProtocolError) {
|
|
652
663
|
closeReason = error.reason;
|
|
653
|
-
debug(
|
|
664
|
+
debug('[HDS %s] Delegate signaled to close the recording stream %d.', this.connection.remoteAddress, this.streamId);
|
|
654
665
|
}
|
|
655
|
-
else if (error instanceof
|
|
666
|
+
else if (error instanceof HDSConnectionError && error.type === 2 /* HDSConnectionErrorType.CLOSED_SOCKET */) {
|
|
656
667
|
// we are probably on a shutdown or just late. Connection is dead. End the stream!
|
|
657
|
-
debug(
|
|
668
|
+
debug('[HDS %s] Exited recording stream due to closed HDS socket: stream id %d.', this.connection.remoteAddress, this.streamId);
|
|
658
669
|
return; // execute finally and then exit (we want to skip the `sendEvent` below)
|
|
659
670
|
}
|
|
660
671
|
else {
|
|
@@ -677,19 +688,17 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
677
688
|
this.kickOffCloseTimeout();
|
|
678
689
|
}
|
|
679
690
|
}
|
|
680
|
-
debug(
|
|
691
|
+
debug('[HDS %s] Finished DATA_SEND transmission for stream %d!', this.connection.remoteAddress, this.streamId);
|
|
681
692
|
}
|
|
682
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
683
693
|
handleDataSendAck(message) {
|
|
684
694
|
const streamId = message.streamId;
|
|
685
695
|
const endOfStream = message.endOfStream;
|
|
686
696
|
// The HomeKit Controller will send a DATA_SEND ACK if we set the `endOfStream` flag in the last packet
|
|
687
697
|
// of our DATA_SEND DATA packet.
|
|
688
698
|
// To my testing the session is then considered complete and the HomeKit controller will close the HDS Connection after 5 seconds.
|
|
689
|
-
debug(
|
|
699
|
+
debug('[HDS %s] Received DATA_SEND ACK packet for streamId %s. Acknowledged %s.', this.connection.remoteAddress, streamId, endOfStream);
|
|
690
700
|
this.handleClosed(() => this.delegate.acknowledgeStream?.(this.streamId));
|
|
691
701
|
}
|
|
692
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
693
702
|
handleDataSendClose(message) {
|
|
694
703
|
// see https://github.com/Supereg/secure-video-specification#43-close
|
|
695
704
|
const streamId = message.streamId;
|
|
@@ -697,13 +706,13 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
697
706
|
if (streamId !== this.streamId) {
|
|
698
707
|
return;
|
|
699
708
|
}
|
|
700
|
-
debug(
|
|
709
|
+
debug('[HDS %s] Received DATA_SEND CLOSE for streamId %d with reason %s',
|
|
701
710
|
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
702
|
-
this.connection.remoteAddress, streamId,
|
|
711
|
+
this.connection.remoteAddress, streamId, HDSProtocolSpecificErrorReason[reason]);
|
|
703
712
|
this.handleClosed(() => this.delegate.closeRecordingStream(streamId, reason));
|
|
704
713
|
}
|
|
705
714
|
handleDataStreamConnectionClosed() {
|
|
706
|
-
debug(
|
|
715
|
+
debug('[HDS %s] The HDS connection of the stream %d closed.', this.connection.remoteAddress, this.streamId);
|
|
707
716
|
this.handleClosed(() => this.delegate.closeRecordingStream(this.streamId, undefined));
|
|
708
717
|
}
|
|
709
718
|
handleClosed(closure) {
|
|
@@ -718,8 +727,8 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
718
727
|
// when this variable is defined, the generator hasn't returned yet.
|
|
719
728
|
// we start a timeout to uncover potential programming mistakes where we await forever and can't free resources.
|
|
720
729
|
this.generatorTimeout = setTimeout(() => {
|
|
721
|
-
console.error(
|
|
722
|
-
|
|
730
|
+
console.error('[HDS %s] Recording download stream %d is still awaiting generator although stream was closed 10s ago! '
|
|
731
|
+
+ 'This is a programming mistake by the camera implementation which prevents freeing up resources.', this.connection.remoteAddress, this.streamId);
|
|
723
732
|
}, 10000);
|
|
724
733
|
}
|
|
725
734
|
try {
|
|
@@ -738,14 +747,14 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
738
747
|
if (this.closed) {
|
|
739
748
|
return;
|
|
740
749
|
}
|
|
741
|
-
debug(
|
|
750
|
+
debug('[HDS %s] Recording stream %d was closed manually with reason %s.',
|
|
742
751
|
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
743
|
-
this.connection.remoteAddress, this.streamId, reason ?
|
|
752
|
+
this.connection.remoteAddress, this.streamId, reason ? HDSProtocolSpecificErrorReason[reason] : 'CLOSED');
|
|
744
753
|
// the `isConsideredClosed` check just ensures that the won't ever throw here and that `handledClosed` is always executed.
|
|
745
754
|
if (!this.connection.isConsideredClosed()) {
|
|
746
755
|
this.connection.sendEvent("dataSend" /* Protocols.DATA_SEND */, "close" /* Topics.CLOSE */, {
|
|
747
756
|
streamId: this.streamId,
|
|
748
|
-
reason
|
|
757
|
+
reason,
|
|
749
758
|
});
|
|
750
759
|
}
|
|
751
760
|
this.handleClosed(() => this.delegate.closeRecordingStream(this.streamId, reason));
|
|
@@ -758,7 +767,7 @@ class CameraRecordingStream extends events_1.EventEmitter {
|
|
|
758
767
|
if (this.closed) {
|
|
759
768
|
return;
|
|
760
769
|
}
|
|
761
|
-
debug(
|
|
770
|
+
debug('[HDS %s] Recording stream %d took longer than expected to fully close. Force closing now!', this.connection.remoteAddress, this.streamId);
|
|
762
771
|
this.close(3 /* HDSProtocolSpecificErrorReason.CANCELLED */);
|
|
763
772
|
}, 12000);
|
|
764
773
|
}
|