hap-nodejs 0.9.8 → 0.10.0-beta.11

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.
Files changed (191) hide show
  1. package/@types/bonjour-hap.d.ts +4 -3
  2. package/@types/simple-plist.d.ts +2 -1
  3. package/dist/BridgedCore.js +5 -4
  4. package/dist/BridgedCore.js.map +1 -1
  5. package/dist/Core.js +12 -10
  6. package/dist/Core.js.map +1 -1
  7. package/dist/accessories/AirConditioner_accessory.js +9 -9
  8. package/dist/accessories/AirConditioner_accessory.js.map +1 -1
  9. package/dist/accessories/AppleTVRemote_accessory.js +9 -8
  10. package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
  11. package/dist/accessories/Camera_accessory.js +414 -35
  12. package/dist/accessories/Camera_accessory.js.map +1 -1
  13. package/dist/accessories/Fan_accessory.js +6 -11
  14. package/dist/accessories/Fan_accessory.js.map +1 -1
  15. package/dist/accessories/GarageDoorOpener_accessory.js +7 -8
  16. package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
  17. package/dist/accessories/Light-AdaptiveLighting_accessory.js +3 -4
  18. package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
  19. package/dist/accessories/Light_accessory.js +23 -14
  20. package/dist/accessories/Light_accessory.js.map +1 -1
  21. package/dist/accessories/Lock_accessory.js +7 -8
  22. package/dist/accessories/Lock_accessory.js.map +1 -1
  23. package/dist/accessories/MotionSensor_accessory.js +5 -6
  24. package/dist/accessories/MotionSensor_accessory.js.map +1 -1
  25. package/dist/accessories/Outlet_accessory.js +5 -6
  26. package/dist/accessories/Outlet_accessory.js.map +1 -1
  27. package/dist/accessories/SmartSpeaker_accessory.js +6 -6
  28. package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
  29. package/dist/accessories/Sprinkler_accessory.js +12 -13
  30. package/dist/accessories/Sprinkler_accessory.js.map +1 -1
  31. package/dist/accessories/TV_accessory.js +4 -5
  32. package/dist/accessories/TV_accessory.js.map +1 -1
  33. package/dist/accessories/TemperatureSensor_accessory.js +5 -6
  34. package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
  35. package/dist/accessories/Wi-FiRouter_accessory.d.ts +1 -1
  36. package/dist/accessories/Wi-FiRouter_accessory.d.ts.map +1 -1
  37. package/dist/accessories/Wi-FiRouter_accessory.js +7 -8
  38. package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
  39. package/dist/accessories/Wi-FiSatellite_accessory.d.ts +1 -1
  40. package/dist/accessories/Wi-FiSatellite_accessory.d.ts.map +1 -1
  41. package/dist/accessories/Wi-FiSatellite_accessory.js +6 -7
  42. package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
  43. package/dist/accessories/gstreamer-audioProducer.d.ts.map +1 -1
  44. package/dist/accessories/gstreamer-audioProducer.js +14 -15
  45. package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
  46. package/dist/index.d.ts +22 -22
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +2 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/internal-types.d.ts +2 -0
  51. package/dist/internal-types.d.ts.map +1 -1
  52. package/dist/internal-types.js.map +1 -1
  53. package/dist/lib/Accessory.d.ts +18 -14
  54. package/dist/lib/Accessory.d.ts.map +1 -1
  55. package/dist/lib/Accessory.js +242 -203
  56. package/dist/lib/Accessory.js.map +1 -1
  57. package/dist/lib/AccessoryLoader.d.ts +10 -10
  58. package/dist/lib/AccessoryLoader.d.ts.map +1 -1
  59. package/dist/lib/AccessoryLoader.js +105 -95
  60. package/dist/lib/AccessoryLoader.js.map +1 -1
  61. package/dist/lib/Advertiser.d.ts +24 -4
  62. package/dist/lib/Advertiser.d.ts.map +1 -1
  63. package/dist/lib/Advertiser.js +215 -10
  64. package/dist/lib/Advertiser.js.map +1 -1
  65. package/dist/lib/Bridge.d.ts +1 -1
  66. package/dist/lib/Bridge.d.ts.map +1 -1
  67. package/dist/lib/Bridge.js.map +1 -1
  68. package/dist/lib/Characteristic.d.ts +22 -21
  69. package/dist/lib/Characteristic.d.ts.map +1 -1
  70. package/dist/lib/Characteristic.js +100 -97
  71. package/dist/lib/Characteristic.js.map +1 -1
  72. package/dist/lib/HAPServer.d.ts +2 -2
  73. package/dist/lib/HAPServer.d.ts.map +1 -1
  74. package/dist/lib/HAPServer.js +18 -14
  75. package/dist/lib/HAPServer.js.map +1 -1
  76. package/dist/lib/Service.d.ts +3 -3
  77. package/dist/lib/Service.d.ts.map +1 -1
  78. package/dist/lib/Service.js +26 -26
  79. package/dist/lib/Service.js.map +1 -1
  80. package/dist/lib/camera/Camera.d.ts +2 -2
  81. package/dist/lib/camera/Camera.d.ts.map +1 -1
  82. package/dist/lib/camera/Camera.js +3 -3
  83. package/dist/lib/camera/Camera.js.map +1 -1
  84. package/dist/lib/camera/RTPProxy.d.ts +19 -19
  85. package/dist/lib/camera/RTPProxy.d.ts.map +1 -1
  86. package/dist/lib/camera/RTPProxy.js +229 -207
  87. package/dist/lib/camera/RTPProxy.js.map +1 -1
  88. package/dist/lib/camera/RTPStreamManagement.d.ts +44 -8
  89. package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
  90. package/dist/lib/camera/RTPStreamManagement.js +111 -37
  91. package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
  92. package/dist/lib/camera/RecordingManagement.d.ts +267 -0
  93. package/dist/lib/camera/RecordingManagement.d.ts.map +1 -0
  94. package/dist/lib/camera/RecordingManagement.js +750 -0
  95. package/dist/lib/camera/RecordingManagement.js.map +1 -0
  96. package/dist/lib/camera/index.d.ts +4 -3
  97. package/dist/lib/camera/index.d.ts.map +1 -1
  98. package/dist/lib/camera/index.js +1 -0
  99. package/dist/lib/camera/index.js.map +1 -1
  100. package/dist/lib/controller/AdaptiveLightingController.d.ts +9 -9
  101. package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
  102. package/dist/lib/controller/AdaptiveLightingController.js +25 -19
  103. package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
  104. package/dist/lib/controller/CameraController.d.ts +253 -7
  105. package/dist/lib/controller/CameraController.d.ts.map +1 -1
  106. package/dist/lib/controller/CameraController.js +378 -31
  107. package/dist/lib/controller/CameraController.js.map +1 -1
  108. package/dist/lib/controller/Controller.d.ts +3 -3
  109. package/dist/lib/controller/Controller.d.ts.map +1 -1
  110. package/dist/lib/controller/Controller.js.map +1 -1
  111. package/dist/lib/controller/DoorbellController.d.ts +43 -1
  112. package/dist/lib/controller/DoorbellController.d.ts.map +1 -1
  113. package/dist/lib/controller/DoorbellController.js +63 -11
  114. package/dist/lib/controller/DoorbellController.js.map +1 -1
  115. package/dist/lib/controller/RemoteController.d.ts +4 -4
  116. package/dist/lib/controller/RemoteController.d.ts.map +1 -1
  117. package/dist/lib/controller/RemoteController.js +62 -52
  118. package/dist/lib/controller/RemoteController.js.map +1 -1
  119. package/dist/lib/controller/index.d.ts +4 -4
  120. package/dist/lib/datastream/DataStreamManagement.d.ts.map +1 -1
  121. package/dist/lib/datastream/DataStreamManagement.js +10 -9
  122. package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
  123. package/dist/lib/datastream/DataStreamParser.d.ts +24 -24
  124. package/dist/lib/datastream/DataStreamParser.d.ts.map +1 -1
  125. package/dist/lib/datastream/DataStreamParser.js +16 -7
  126. package/dist/lib/datastream/DataStreamParser.js.map +1 -1
  127. package/dist/lib/datastream/DataStreamServer.d.ts +24 -5
  128. package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
  129. package/dist/lib/datastream/DataStreamServer.js +100 -59
  130. package/dist/lib/datastream/DataStreamServer.js.map +1 -1
  131. package/dist/lib/datastream/index.d.ts +3 -3
  132. package/dist/lib/definitions/generate-definitions.d.ts.map +1 -1
  133. package/dist/lib/definitions/generate-definitions.js +18 -14
  134. package/dist/lib/definitions/generate-definitions.js.map +1 -1
  135. package/dist/lib/definitions/generator-configuration.d.ts.map +1 -1
  136. package/dist/lib/definitions/generator-configuration.js +32 -14
  137. package/dist/lib/definitions/generator-configuration.js.map +1 -1
  138. package/dist/lib/model/AccessoryInfo.d.ts +6 -6
  139. package/dist/lib/model/AccessoryInfo.d.ts.map +1 -1
  140. package/dist/lib/model/AccessoryInfo.js +79 -69
  141. package/dist/lib/model/AccessoryInfo.js.map +1 -1
  142. package/dist/lib/model/ControllerStorage.d.ts.map +1 -1
  143. package/dist/lib/model/ControllerStorage.js +3 -3
  144. package/dist/lib/model/ControllerStorage.js.map +1 -1
  145. package/dist/lib/model/HAPStorage.d.ts.map +1 -1
  146. package/dist/lib/model/HAPStorage.js +1 -0
  147. package/dist/lib/model/HAPStorage.js.map +1 -1
  148. package/dist/lib/model/IdentifierCache.d.ts +11 -11
  149. package/dist/lib/model/IdentifierCache.d.ts.map +1 -1
  150. package/dist/lib/model/IdentifierCache.js +67 -65
  151. package/dist/lib/model/IdentifierCache.js.map +1 -1
  152. package/dist/lib/tv/AccessControlManagement.d.ts +1 -1
  153. package/dist/lib/tv/AccessControlManagement.d.ts.map +1 -1
  154. package/dist/lib/tv/AccessControlManagement.js.map +1 -1
  155. package/dist/lib/util/clone.js +1 -0
  156. package/dist/lib/util/clone.js.map +1 -1
  157. package/dist/lib/util/color-utils.d.ts.map +1 -1
  158. package/dist/lib/util/color-utils.js +1 -1
  159. package/dist/lib/util/color-utils.js.map +1 -1
  160. package/dist/lib/util/eventedhttp.d.ts +4 -4
  161. package/dist/lib/util/eventedhttp.d.ts.map +1 -1
  162. package/dist/lib/util/eventedhttp.js +25 -22
  163. package/dist/lib/util/eventedhttp.js.map +1 -1
  164. package/dist/lib/util/hapCrypto.d.ts +5 -5
  165. package/dist/lib/util/hapCrypto.d.ts.map +1 -1
  166. package/dist/lib/util/hapCrypto.js +57 -86
  167. package/dist/lib/util/hapCrypto.js.map +1 -1
  168. package/dist/lib/util/hapStatusError.js +1 -1
  169. package/dist/lib/util/net-utils.d.ts.map +1 -1
  170. package/dist/lib/util/net-utils.js +0 -2
  171. package/dist/lib/util/net-utils.js.map +1 -1
  172. package/dist/lib/util/once.d.ts +1 -1
  173. package/dist/lib/util/once.d.ts.map +1 -1
  174. package/dist/lib/util/once.js +1 -0
  175. package/dist/lib/util/once.js.map +1 -1
  176. package/dist/lib/util/request-util.d.ts.map +1 -1
  177. package/dist/lib/util/request-util.js +1 -0
  178. package/dist/lib/util/request-util.js.map +1 -1
  179. package/dist/lib/util/time.d.ts +1 -1
  180. package/dist/lib/util/time.d.ts.map +1 -1
  181. package/dist/lib/util/time.js +5 -5
  182. package/dist/lib/util/time.js.map +1 -1
  183. package/dist/lib/util/tlv.d.ts.map +1 -1
  184. package/dist/lib/util/tlv.js +9 -6
  185. package/dist/lib/util/tlv.js.map +1 -1
  186. package/dist/lib/util/uuid.d.ts.map +1 -1
  187. package/dist/lib/util/uuid.js +25 -19
  188. package/dist/lib/util/uuid.js.map +1 -1
  189. package/dist/types.d.ts +0 -1
  190. package/dist/types.d.ts.map +1 -1
  191. package/package.json +16 -12
@@ -0,0 +1,750 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RecordingManagement = exports.PacketDataType = exports.AudioRecordingSamplerate = exports.AudioRecordingCodecType = exports.MediaContainerType = exports.EventTriggerOption = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var crypto_1 = (0, tslib_1.__importDefault)(require("crypto"));
6
+ var debug_1 = (0, tslib_1.__importDefault)(require("debug"));
7
+ var events_1 = require("events");
8
+ var Characteristic_1 = require("../Characteristic");
9
+ var datastream_1 = require("../datastream");
10
+ var Service_1 = require("../Service");
11
+ var hapStatusError_1 = require("../util/hapStatusError");
12
+ var tlv = (0, tslib_1.__importStar)(require("../util/tlv"));
13
+ var debug = (0, debug_1.default)("HAP-NodeJS:Camera:RecordingManagement");
14
+ /**
15
+ * Describes the Event trigger.
16
+ */
17
+ var EventTriggerOption;
18
+ (function (EventTriggerOption) {
19
+ /**
20
+ * The Motion trigger. If enabled motion should trigger the start of a recording.
21
+ */
22
+ EventTriggerOption[EventTriggerOption["MOTION"] = 1] = "MOTION";
23
+ /**
24
+ * The Doorbell trigger. If enabled a doorbell button press should trigger the start of a recording.
25
+ */
26
+ EventTriggerOption[EventTriggerOption["DOORBELL"] = 2] = "DOORBELL";
27
+ })(EventTriggerOption = exports.EventTriggerOption || (exports.EventTriggerOption = {}));
28
+ var MediaContainerType;
29
+ (function (MediaContainerType) {
30
+ MediaContainerType[MediaContainerType["FRAGMENTED_MP4"] = 0] = "FRAGMENTED_MP4";
31
+ })(MediaContainerType = exports.MediaContainerType || (exports.MediaContainerType = {}));
32
+ var VideoCodecConfigurationTypes;
33
+ (function (VideoCodecConfigurationTypes) {
34
+ VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE";
35
+ VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS";
36
+ VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["ATTRIBUTES"] = 3] = "ATTRIBUTES";
37
+ })(VideoCodecConfigurationTypes || (VideoCodecConfigurationTypes = {}));
38
+ var VideoCodecParametersTypes;
39
+ (function (VideoCodecParametersTypes) {
40
+ VideoCodecParametersTypes[VideoCodecParametersTypes["PROFILE_ID"] = 1] = "PROFILE_ID";
41
+ VideoCodecParametersTypes[VideoCodecParametersTypes["LEVEL"] = 2] = "LEVEL";
42
+ VideoCodecParametersTypes[VideoCodecParametersTypes["BITRATE"] = 3] = "BITRATE";
43
+ VideoCodecParametersTypes[VideoCodecParametersTypes["IFRAME_INTERVAL"] = 4] = "IFRAME_INTERVAL";
44
+ })(VideoCodecParametersTypes || (VideoCodecParametersTypes = {}));
45
+ var VideoAttributesTypes;
46
+ (function (VideoAttributesTypes) {
47
+ VideoAttributesTypes[VideoAttributesTypes["IMAGE_WIDTH"] = 1] = "IMAGE_WIDTH";
48
+ VideoAttributesTypes[VideoAttributesTypes["IMAGE_HEIGHT"] = 2] = "IMAGE_HEIGHT";
49
+ VideoAttributesTypes[VideoAttributesTypes["FRAME_RATE"] = 3] = "FRAME_RATE";
50
+ })(VideoAttributesTypes || (VideoAttributesTypes = {}));
51
+ var SelectedCameraRecordingConfigurationTypes;
52
+ (function (SelectedCameraRecordingConfigurationTypes) {
53
+ SelectedCameraRecordingConfigurationTypes[SelectedCameraRecordingConfigurationTypes["SELECTED_RECORDING_CONFIGURATION"] = 1] = "SELECTED_RECORDING_CONFIGURATION";
54
+ SelectedCameraRecordingConfigurationTypes[SelectedCameraRecordingConfigurationTypes["SELECTED_VIDEO_CONFIGURATION"] = 2] = "SELECTED_VIDEO_CONFIGURATION";
55
+ SelectedCameraRecordingConfigurationTypes[SelectedCameraRecordingConfigurationTypes["SELECTED_AUDIO_CONFIGURATION"] = 3] = "SELECTED_AUDIO_CONFIGURATION";
56
+ })(SelectedCameraRecordingConfigurationTypes || (SelectedCameraRecordingConfigurationTypes = {}));
57
+ var AudioRecordingCodecType;
58
+ (function (AudioRecordingCodecType) {
59
+ AudioRecordingCodecType[AudioRecordingCodecType["AAC_LC"] = 0] = "AAC_LC";
60
+ AudioRecordingCodecType[AudioRecordingCodecType["AAC_ELD"] = 1] = "AAC_ELD";
61
+ })(AudioRecordingCodecType = exports.AudioRecordingCodecType || (exports.AudioRecordingCodecType = {}));
62
+ var AudioRecordingSamplerate;
63
+ (function (AudioRecordingSamplerate) {
64
+ AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_8"] = 0] = "KHZ_8";
65
+ AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_16"] = 1] = "KHZ_16";
66
+ AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_24"] = 2] = "KHZ_24";
67
+ AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_32"] = 3] = "KHZ_32";
68
+ AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_44_1"] = 4] = "KHZ_44_1";
69
+ AudioRecordingSamplerate[AudioRecordingSamplerate["KHZ_48"] = 5] = "KHZ_48";
70
+ })(AudioRecordingSamplerate = exports.AudioRecordingSamplerate || (exports.AudioRecordingSamplerate = {}));
71
+ var SupportedVideoRecordingConfigurationTypes;
72
+ (function (SupportedVideoRecordingConfigurationTypes) {
73
+ SupportedVideoRecordingConfigurationTypes[SupportedVideoRecordingConfigurationTypes["VIDEO_CODEC_CONFIGURATION"] = 1] = "VIDEO_CODEC_CONFIGURATION";
74
+ })(SupportedVideoRecordingConfigurationTypes || (SupportedVideoRecordingConfigurationTypes = {}));
75
+ var SupportedCameraRecordingConfigurationTypes;
76
+ (function (SupportedCameraRecordingConfigurationTypes) {
77
+ SupportedCameraRecordingConfigurationTypes[SupportedCameraRecordingConfigurationTypes["PREBUFFER_LENGTH"] = 1] = "PREBUFFER_LENGTH";
78
+ SupportedCameraRecordingConfigurationTypes[SupportedCameraRecordingConfigurationTypes["EVENT_TRIGGER_OPTIONS"] = 2] = "EVENT_TRIGGER_OPTIONS";
79
+ SupportedCameraRecordingConfigurationTypes[SupportedCameraRecordingConfigurationTypes["MEDIA_CONTAINER_CONFIGURATIONS"] = 3] = "MEDIA_CONTAINER_CONFIGURATIONS";
80
+ })(SupportedCameraRecordingConfigurationTypes || (SupportedCameraRecordingConfigurationTypes = {}));
81
+ var MediaContainerConfigurationTypes;
82
+ (function (MediaContainerConfigurationTypes) {
83
+ MediaContainerConfigurationTypes[MediaContainerConfigurationTypes["MEDIA_CONTAINER_TYPE"] = 1] = "MEDIA_CONTAINER_TYPE";
84
+ MediaContainerConfigurationTypes[MediaContainerConfigurationTypes["MEDIA_CONTAINER_PARAMETERS"] = 2] = "MEDIA_CONTAINER_PARAMETERS";
85
+ })(MediaContainerConfigurationTypes || (MediaContainerConfigurationTypes = {}));
86
+ var MediaContainerParameterTypes;
87
+ (function (MediaContainerParameterTypes) {
88
+ MediaContainerParameterTypes[MediaContainerParameterTypes["FRAGMENT_LENGTH"] = 1] = "FRAGMENT_LENGTH";
89
+ })(MediaContainerParameterTypes || (MediaContainerParameterTypes = {}));
90
+ var AudioCodecParametersTypes;
91
+ (function (AudioCodecParametersTypes) {
92
+ AudioCodecParametersTypes[AudioCodecParametersTypes["CHANNEL"] = 1] = "CHANNEL";
93
+ AudioCodecParametersTypes[AudioCodecParametersTypes["BIT_RATE"] = 2] = "BIT_RATE";
94
+ AudioCodecParametersTypes[AudioCodecParametersTypes["SAMPLE_RATE"] = 3] = "SAMPLE_RATE";
95
+ AudioCodecParametersTypes[AudioCodecParametersTypes["MAX_AUDIO_BITRATE"] = 4] = "MAX_AUDIO_BITRATE"; // only present in selected audio codec parameters tlv
96
+ })(AudioCodecParametersTypes || (AudioCodecParametersTypes = {}));
97
+ var AudioCodecConfigurationTypes;
98
+ (function (AudioCodecConfigurationTypes) {
99
+ AudioCodecConfigurationTypes[AudioCodecConfigurationTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE";
100
+ AudioCodecConfigurationTypes[AudioCodecConfigurationTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS";
101
+ })(AudioCodecConfigurationTypes || (AudioCodecConfigurationTypes = {}));
102
+ var SupportedAudioRecordingConfigurationTypes;
103
+ (function (SupportedAudioRecordingConfigurationTypes) {
104
+ SupportedAudioRecordingConfigurationTypes[SupportedAudioRecordingConfigurationTypes["AUDIO_CODEC_CONFIGURATION"] = 1] = "AUDIO_CODEC_CONFIGURATION";
105
+ })(SupportedAudioRecordingConfigurationTypes || (SupportedAudioRecordingConfigurationTypes = {}));
106
+ var PacketDataType;
107
+ (function (PacketDataType) {
108
+ // mp4 moov box
109
+ PacketDataType["MEDIA_INITIALIZATION"] = "mediaInitialization";
110
+ // mp4 moof + mdat boxes
111
+ PacketDataType["MEDIA_FRAGMENT"] = "mediaFragment";
112
+ })(PacketDataType = exports.PacketDataType || (exports.PacketDataType = {}));
113
+ var RecordingManagement = /** @class */ (function () {
114
+ function RecordingManagement(options, delegate, eventTriggerOptions, services) {
115
+ var e_1, _a;
116
+ /**
117
+ * Array of sensor services (e.g. {@link Service.MotionSensor} or {@link Service.OccupancySensor}).
118
+ * Any service in this array owns a {@link Characteristic.StatusActive} characteristic.
119
+ * The value of the {@link Characteristic.HomeKitCameraActive} is mirrored towards the {@link Characteristic.StatusActive} characteristic.
120
+ * The array is initialized my the caller shortly after calling the constructor.
121
+ */
122
+ this.sensorServices = [];
123
+ this.options = options;
124
+ this.delegate = delegate;
125
+ var recordingServices = services || this.constructService();
126
+ this.recordingManagementService = recordingServices.recordingManagement;
127
+ this.operatingModeService = recordingServices.operatingMode;
128
+ this.dataStreamManagement = recordingServices.dataStreamManagement;
129
+ this.eventTriggerOptions = 0;
130
+ try {
131
+ for (var eventTriggerOptions_1 = (0, tslib_1.__values)(eventTriggerOptions), eventTriggerOptions_1_1 = eventTriggerOptions_1.next(); !eventTriggerOptions_1_1.done; eventTriggerOptions_1_1 = eventTriggerOptions_1.next()) {
132
+ var option = eventTriggerOptions_1_1.value;
133
+ this.eventTriggerOptions |= option; // OR
134
+ }
135
+ }
136
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
137
+ finally {
138
+ try {
139
+ if (eventTriggerOptions_1_1 && !eventTriggerOptions_1_1.done && (_a = eventTriggerOptions_1.return)) _a.call(eventTriggerOptions_1);
140
+ }
141
+ finally { if (e_1) throw e_1.error; }
142
+ }
143
+ this.supportedCameraRecordingConfiguration = this._supportedCameraRecordingConfiguration(options);
144
+ this.supportedVideoRecordingConfiguration = this._supportedVideoRecordingConfiguration(options.video);
145
+ this.supportedAudioRecordingConfiguration = this._supportedAudioStreamConfiguration(options.audio);
146
+ this.setupServiceHandlers();
147
+ }
148
+ RecordingManagement.prototype.constructService = function () {
149
+ var recordingManagement = new Service_1.Service.CameraRecordingManagement("", "");
150
+ recordingManagement.setCharacteristic(Characteristic_1.Characteristic.Active, false);
151
+ recordingManagement.setCharacteristic(Characteristic_1.Characteristic.RecordingAudioActive, false);
152
+ var operatingMode = new Service_1.Service.CameraOperatingMode("", "");
153
+ operatingMode.setCharacteristic(Characteristic_1.Characteristic.EventSnapshotsActive, true);
154
+ operatingMode.setCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive, true);
155
+ operatingMode.setCharacteristic(Characteristic_1.Characteristic.PeriodicSnapshotsActive, true);
156
+ var dataStreamManagement = new datastream_1.DataStreamManagement();
157
+ recordingManagement.addLinkedService(dataStreamManagement.getService());
158
+ return {
159
+ recordingManagement: recordingManagement,
160
+ operatingMode: operatingMode,
161
+ dataStreamManagement: dataStreamManagement,
162
+ };
163
+ };
164
+ RecordingManagement.prototype.setupServiceHandlers = function () {
165
+ var _this = this;
166
+ // update the current configuration values to the current state.
167
+ this.recordingManagementService.setCharacteristic(Characteristic_1.Characteristic.SupportedCameraRecordingConfiguration, this.supportedCameraRecordingConfiguration);
168
+ this.recordingManagementService.setCharacteristic(Characteristic_1.Characteristic.SupportedVideoRecordingConfiguration, this.supportedVideoRecordingConfiguration);
169
+ this.recordingManagementService.setCharacteristic(Characteristic_1.Characteristic.SupportedAudioRecordingConfiguration, this.supportedAudioRecordingConfiguration);
170
+ this.recordingManagementService.getCharacteristic(Characteristic_1.Characteristic.SelectedCameraRecordingConfiguration)
171
+ .onGet(this.handleSelectedCameraRecordingConfigurationRead.bind(this))
172
+ .onSet(this.handleSelectedCameraRecordingConfigurationWrite.bind(this))
173
+ .setProps({ adminOnlyAccess: [1 /* WRITE */] });
174
+ this.recordingManagementService.getCharacteristic(Characteristic_1.Characteristic.Active)
175
+ .onSet(function (value) { return _this.delegate.updateRecordingActive(!!value); })
176
+ .on("change" /* CHANGE */, function () { var _a; return (_a = _this.stateChangeDelegate) === null || _a === void 0 ? void 0 : _a.call(_this); })
177
+ .setProps({ adminOnlyAccess: [1 /* WRITE */] });
178
+ this.recordingManagementService.getCharacteristic(Characteristic_1.Characteristic.RecordingAudioActive)
179
+ .on("change" /* CHANGE */, function () { var _a; return (_a = _this.stateChangeDelegate) === null || _a === void 0 ? void 0 : _a.call(_this); });
180
+ this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive)
181
+ .on("change" /* CHANGE */, function (change) {
182
+ var e_2, _a;
183
+ var _b;
184
+ try {
185
+ for (var _c = (0, tslib_1.__values)(_this.sensorServices), _d = _c.next(); !_d.done; _d = _c.next()) {
186
+ var service = _d.value;
187
+ service.setCharacteristic(Characteristic_1.Characteristic.StatusActive, !!change.newValue);
188
+ }
189
+ }
190
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
191
+ finally {
192
+ try {
193
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
194
+ }
195
+ finally { if (e_2) throw e_2.error; }
196
+ }
197
+ if (!change.newValue && _this.recordingStream) {
198
+ _this.recordingStream.close(1 /* NOT_ALLOWED */);
199
+ }
200
+ (_b = _this.stateChangeDelegate) === null || _b === void 0 ? void 0 : _b.call(_this);
201
+ })
202
+ .setProps({ adminOnlyAccess: [1 /* WRITE */] });
203
+ this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.EventSnapshotsActive)
204
+ .on("change" /* CHANGE */, function () { var _a; return (_a = _this.stateChangeDelegate) === null || _a === void 0 ? void 0 : _a.call(_this); })
205
+ .setProps({ adminOnlyAccess: [1 /* WRITE */] });
206
+ this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.PeriodicSnapshotsActive)
207
+ .on("change" /* CHANGE */, function () { var _a; return (_a = _this.stateChangeDelegate) === null || _a === void 0 ? void 0 : _a.call(_this); })
208
+ .setProps({ adminOnlyAccess: [1 /* WRITE */] });
209
+ this.dataStreamManagement
210
+ .onRequestMessage("dataSend" /* DATA_SEND */, "open" /* OPEN */, this.handleDataSendOpen.bind(this));
211
+ };
212
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
213
+ RecordingManagement.prototype.handleDataSendOpen = function (connection, id, message) {
214
+ var _this = this;
215
+ // for message fields see https://github.com/Supereg/secure-video-specification#41-start
216
+ var streamId = message.streamId;
217
+ var type = message.type;
218
+ var target = message.target;
219
+ var reason = message.reason;
220
+ if (target !== "controller" || type !== "ipcamera.recording") {
221
+ debug("[HDS %s] Received data send with unexpected target: %s or type: %d. Rejecting...", connection.remoteAddress, target, type);
222
+ connection.sendResponse("dataSend" /* DATA_SEND */, "open" /* OPEN */, id, datastream_1.HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
223
+ status: 5 /* UNEXPECTED_FAILURE */,
224
+ });
225
+ return;
226
+ }
227
+ if (!this.recordingManagementService.getCharacteristic(Characteristic_1.Characteristic.Active).value) {
228
+ connection.sendResponse("dataSend" /* DATA_SEND */, "open" /* OPEN */, id, datastream_1.HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
229
+ status: 1 /* NOT_ALLOWED */,
230
+ });
231
+ return;
232
+ }
233
+ if (!this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive).value) {
234
+ connection.sendResponse("dataSend" /* DATA_SEND */, "open" /* OPEN */, id, datastream_1.HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
235
+ status: 1 /* NOT_ALLOWED */,
236
+ });
237
+ return;
238
+ }
239
+ if (this.recordingStream) {
240
+ 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);
241
+ // there is already a recording stream running.
242
+ connection.sendResponse("dataSend" /* DATA_SEND */, "open" /* OPEN */, id, datastream_1.HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
243
+ status: 2 /* BUSY */,
244
+ });
245
+ return;
246
+ }
247
+ if (!this.selectedConfiguration) {
248
+ connection.sendResponse("dataSend" /* DATA_SEND */, "open" /* OPEN */, id, datastream_1.HDSStatus.PROTOCOL_SPECIFIC_ERROR, {
249
+ status: 9 /* INVALID_CONFIGURATION */,
250
+ });
251
+ return;
252
+ }
253
+ debug("[HDS %s] HDS DATA_SEND Open with reason '%s'.", connection.remoteAddress, reason);
254
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
255
+ this.recordingStream = new CameraRecordingStream(connection, this.delegate, id, streamId);
256
+ this.recordingStream.on("closed" /* CLOSED */, function () {
257
+ _this.recordingStream = undefined;
258
+ });
259
+ this.recordingStream.startStreaming();
260
+ };
261
+ RecordingManagement.prototype.handleSelectedCameraRecordingConfigurationRead = function () {
262
+ if (!this.selectedConfiguration) {
263
+ throw new hapStatusError_1.HapStatusError(-70402 /* SERVICE_COMMUNICATION_FAILURE */);
264
+ }
265
+ return this.selectedConfiguration.base64;
266
+ };
267
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
268
+ RecordingManagement.prototype.handleSelectedCameraRecordingConfigurationWrite = function (value) {
269
+ var _a;
270
+ var configuration = this.parseSelectedConfiguration(value);
271
+ this.selectedConfiguration = {
272
+ parsed: configuration,
273
+ base64: value,
274
+ };
275
+ this.delegate.updateRecordingConfiguration(this.selectedConfiguration.parsed);
276
+ // notify controller storage about updated values!
277
+ (_a = this.stateChangeDelegate) === null || _a === void 0 ? void 0 : _a.call(this);
278
+ };
279
+ RecordingManagement.prototype.parseSelectedConfiguration = function (value) {
280
+ var decoded = tlv.decode(Buffer.from(value, "base64"));
281
+ var recording = tlv.decode(decoded[1 /* SELECTED_RECORDING_CONFIGURATION */]);
282
+ var video = tlv.decode(decoded[2 /* SELECTED_VIDEO_CONFIGURATION */]);
283
+ var audio = tlv.decode(decoded[3 /* SELECTED_AUDIO_CONFIGURATION */]);
284
+ var prebufferLength = recording[1 /* PREBUFFER_LENGTH */].readInt32LE(0);
285
+ var eventTriggerOptions = recording[2 /* EVENT_TRIGGER_OPTIONS */].readInt32LE(0);
286
+ var mediaContainerConfiguration = tlv.decode(recording[3 /* MEDIA_CONTAINER_CONFIGURATIONS */]);
287
+ var containerType = mediaContainerConfiguration[1 /* MEDIA_CONTAINER_TYPE */][0];
288
+ var mediaContainerParameters = tlv.decode(mediaContainerConfiguration[2 /* MEDIA_CONTAINER_PARAMETERS */]);
289
+ var fragmentLength = mediaContainerParameters[1 /* FRAGMENT_LENGTH */].readInt32LE(0);
290
+ var videoCodec = video[1 /* CODEC_TYPE */][0];
291
+ var videoParameters = tlv.decode(video[2 /* CODEC_PARAMETERS */]);
292
+ var videoAttributes = tlv.decode(video[3 /* ATTRIBUTES */]);
293
+ var profile = videoParameters[1 /* PROFILE_ID */][0];
294
+ var level = videoParameters[2 /* LEVEL */][0];
295
+ var videoBitrate = videoParameters[3 /* BITRATE */].readInt32LE(0);
296
+ var iFrameInterval = videoParameters[4 /* IFRAME_INTERVAL */].readInt32LE(0);
297
+ var width = videoAttributes[1 /* IMAGE_WIDTH */].readInt16LE(0);
298
+ var height = videoAttributes[2 /* IMAGE_HEIGHT */].readInt16LE(0);
299
+ var framerate = videoAttributes[3 /* FRAME_RATE */][0];
300
+ var audioCodec = audio[1 /* CODEC_TYPE */][0];
301
+ var audioParameters = tlv.decode(audio[2 /* CODEC_PARAMETERS */]);
302
+ var audioChannels = audioParameters[1 /* CHANNEL */][0];
303
+ var samplerate = audioParameters[3 /* SAMPLE_RATE */][0];
304
+ var audioBitrateMode = audioParameters[2 /* BIT_RATE */][0];
305
+ var audioBitrate = audioParameters[4 /* MAX_AUDIO_BITRATE */].readUInt32LE(0);
306
+ var typedEventTriggers = [];
307
+ var bit_index = 0;
308
+ while (eventTriggerOptions > 0) {
309
+ if (eventTriggerOptions & 0x01) { // of the lowest bit is set add the next event trigger option
310
+ typedEventTriggers.push(1 << bit_index);
311
+ }
312
+ eventTriggerOptions = eventTriggerOptions >> 1; // shift to right till we reach zero.
313
+ bit_index += 1; // count our current bit index
314
+ }
315
+ return {
316
+ prebufferLength: prebufferLength,
317
+ eventTriggerTypes: typedEventTriggers,
318
+ mediaContainerConfiguration: {
319
+ type: containerType,
320
+ fragmentLength: fragmentLength,
321
+ },
322
+ videoCodec: {
323
+ type: videoCodec,
324
+ parameters: {
325
+ profile: profile,
326
+ level: level,
327
+ bitRate: videoBitrate,
328
+ iFrameInterval: iFrameInterval,
329
+ },
330
+ resolution: [width, height, framerate],
331
+ },
332
+ audioCodec: {
333
+ audioChannels: audioChannels,
334
+ type: audioCodec,
335
+ samplerate: samplerate,
336
+ bitrateMode: audioBitrateMode,
337
+ bitrate: audioBitrate,
338
+ },
339
+ };
340
+ };
341
+ RecordingManagement.prototype._supportedCameraRecordingConfiguration = function (options) {
342
+ var mediaContainers = Array.isArray(options.mediaContainerConfiguration)
343
+ ? options.mediaContainerConfiguration
344
+ : [options.mediaContainerConfiguration];
345
+ var prebufferLength = Buffer.alloc(4);
346
+ var eventTriggerOptions = Buffer.alloc(8);
347
+ prebufferLength.writeInt32LE(options.prebufferLength, 0);
348
+ eventTriggerOptions.writeInt32LE(this.eventTriggerOptions, 0);
349
+ return tlv.encode(1 /* PREBUFFER_LENGTH */, prebufferLength, 2 /* EVENT_TRIGGER_OPTIONS */, eventTriggerOptions, 3 /* MEDIA_CONTAINER_CONFIGURATIONS */, mediaContainers.map(function (config) {
350
+ var fragmentLength = Buffer.alloc(4);
351
+ fragmentLength.writeInt32LE(config.fragmentLength, 0);
352
+ return tlv.encode(1 /* MEDIA_CONTAINER_TYPE */, config.type, 2 /* MEDIA_CONTAINER_PARAMETERS */, tlv.encode(1 /* FRAGMENT_LENGTH */, fragmentLength));
353
+ })).toString("base64");
354
+ };
355
+ RecordingManagement.prototype._supportedVideoRecordingConfiguration = function (videoOptions) {
356
+ if (!videoOptions.parameters) {
357
+ throw new Error("Video parameters cannot be undefined");
358
+ }
359
+ if (!videoOptions.resolutions) {
360
+ throw new Error("Video resolutions cannot be undefined");
361
+ }
362
+ var codecParameters = tlv.encode(1 /* PROFILE_ID */, videoOptions.parameters.profiles, 2 /* LEVEL */, videoOptions.parameters.levels);
363
+ var videoStreamConfiguration = tlv.encode(1 /* CODEC_TYPE */, videoOptions.type, 2 /* CODEC_PARAMETERS */, codecParameters, 3 /* ATTRIBUTES */, videoOptions.resolutions.map(function (resolution) {
364
+ if (resolution.length !== 3) {
365
+ throw new Error("Unexpected video resolution");
366
+ }
367
+ var width = Buffer.alloc(2);
368
+ var height = Buffer.alloc(2);
369
+ var frameRate = Buffer.alloc(1);
370
+ width.writeUInt16LE(resolution[0], 0);
371
+ height.writeUInt16LE(resolution[1], 0);
372
+ frameRate.writeUInt8(resolution[2], 0);
373
+ return tlv.encode(1 /* IMAGE_WIDTH */, width, 2 /* IMAGE_HEIGHT */, height, 3 /* FRAME_RATE */, frameRate);
374
+ }));
375
+ return tlv.encode(1 /* VIDEO_CODEC_CONFIGURATION */, videoStreamConfiguration).toString("base64");
376
+ };
377
+ RecordingManagement.prototype._supportedAudioStreamConfiguration = function (audioOptions) {
378
+ var audioCodecs = Array.isArray(audioOptions.codecs)
379
+ ? audioOptions.codecs
380
+ : [audioOptions.codecs];
381
+ if (audioCodecs.length === 0) {
382
+ throw Error("CameraRecordingOptions.audio: At least one audio codec configuration must be specified!");
383
+ }
384
+ var codecConfigurations = audioCodecs.map(function (codec) {
385
+ var providedSamplerates = Array.isArray(codec.samplerate)
386
+ ? codec.samplerate
387
+ : [codec.samplerate];
388
+ if (providedSamplerates.length === 0) {
389
+ throw new Error("CameraRecordingOptions.audio.codecs: Audio samplerate cannot be empty!");
390
+ }
391
+ var audioParameters = tlv.encode(1 /* CHANNEL */, Math.max(1, codec.audioChannels || 1), 2 /* BIT_RATE */, codec.bitrateMode || 0 /* VARIABLE */, 3 /* SAMPLE_RATE */, providedSamplerates);
392
+ return tlv.encode(1 /* CODEC_TYPE */, codec.type, 2 /* CODEC_PARAMETERS */, audioParameters);
393
+ });
394
+ return tlv.encode(1 /* AUDIO_CODEC_CONFIGURATION */, codecConfigurations).toString("base64");
395
+ };
396
+ RecordingManagement.prototype.computeConfigurationHash = function (algorithm) {
397
+ if (algorithm === void 0) { algorithm = "sha256"; }
398
+ var configurationHash = crypto_1.default.createHash(algorithm);
399
+ configurationHash.update(this.supportedCameraRecordingConfiguration);
400
+ configurationHash.update(this.supportedVideoRecordingConfiguration);
401
+ configurationHash.update(this.supportedAudioRecordingConfiguration);
402
+ return configurationHash.digest().toString("hex");
403
+ };
404
+ /**
405
+ * @private
406
+ */
407
+ RecordingManagement.prototype.serialize = function () {
408
+ var _a;
409
+ return {
410
+ configurationHash: {
411
+ algorithm: "sha256",
412
+ hash: this.computeConfigurationHash("sha256"),
413
+ },
414
+ selectedConfiguration: (_a = this.selectedConfiguration) === null || _a === void 0 ? void 0 : _a.base64,
415
+ recordingActive: !!this.recordingManagementService.getCharacteristic(Characteristic_1.Characteristic.Active).value,
416
+ recordingAudioActive: !!this.recordingManagementService.getCharacteristic(Characteristic_1.Characteristic.RecordingAudioActive).value,
417
+ eventSnapshotsActive: !!this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.EventSnapshotsActive).value,
418
+ homeKitCameraActive: !!this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive).value,
419
+ periodicSnapshotsActive: !!this.operatingModeService.getCharacteristic(Characteristic_1.Characteristic.PeriodicSnapshotsActive).value,
420
+ };
421
+ };
422
+ /**
423
+ * @private
424
+ */
425
+ RecordingManagement.prototype.deserialize = function (serialized) {
426
+ var e_3, _a;
427
+ var _b;
428
+ var changedState = false;
429
+ // we only restore the `selectedConfiguration` if our supported configuration hasn't changed.
430
+ var currentConfigurationHash = this.computeConfigurationHash(serialized.configurationHash.algorithm);
431
+ if (serialized.selectedConfiguration) {
432
+ if (currentConfigurationHash === serialized.configurationHash.hash) {
433
+ this.selectedConfiguration = {
434
+ base64: serialized.selectedConfiguration,
435
+ parsed: this.parseSelectedConfiguration(serialized.selectedConfiguration),
436
+ };
437
+ }
438
+ else {
439
+ changedState = true;
440
+ }
441
+ }
442
+ this.recordingManagementService.updateCharacteristic(Characteristic_1.Characteristic.Active, serialized.recordingActive);
443
+ this.recordingManagementService.updateCharacteristic(Characteristic_1.Characteristic.RecordingAudioActive, serialized.recordingAudioActive);
444
+ this.operatingModeService.updateCharacteristic(Characteristic_1.Characteristic.EventSnapshotsActive, serialized.eventSnapshotsActive);
445
+ this.operatingModeService.updateCharacteristic(Characteristic_1.Characteristic.PeriodicSnapshotsActive, serialized.periodicSnapshotsActive);
446
+ this.operatingModeService.updateCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive, serialized.homeKitCameraActive);
447
+ try {
448
+ for (var _c = (0, tslib_1.__values)(this.sensorServices), _d = _c.next(); !_d.done; _d = _c.next()) {
449
+ var service = _d.value;
450
+ service.setCharacteristic(Characteristic_1.Characteristic.StatusActive, serialized.homeKitCameraActive);
451
+ }
452
+ }
453
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
454
+ finally {
455
+ try {
456
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
457
+ }
458
+ finally { if (e_3) throw e_3.error; }
459
+ }
460
+ try {
461
+ if (this.selectedConfiguration) {
462
+ this.delegate.updateRecordingConfiguration(this.selectedConfiguration.parsed);
463
+ }
464
+ if (serialized.recordingActive) {
465
+ this.delegate.updateRecordingActive(serialized.recordingActive);
466
+ }
467
+ }
468
+ catch (error) {
469
+ console.error("Failed to properly initialize CameraRecordingDelegate from persistent storage: " + error.stack);
470
+ }
471
+ if (changedState) {
472
+ (_b = this.stateChangeDelegate) === null || _b === void 0 ? void 0 : _b.call(this);
473
+ }
474
+ };
475
+ /**
476
+ * @private
477
+ */
478
+ RecordingManagement.prototype.setupStateChangeDelegate = function (delegate) {
479
+ this.stateChangeDelegate = delegate;
480
+ };
481
+ RecordingManagement.prototype.destroy = function () {
482
+ this.dataStreamManagement.destroy();
483
+ };
484
+ RecordingManagement.prototype.handleFactoryReset = function () {
485
+ var e_4, _a;
486
+ this.selectedConfiguration = undefined;
487
+ this.recordingManagementService.updateCharacteristic(Characteristic_1.Characteristic.Active, false);
488
+ this.recordingManagementService.updateCharacteristic(Characteristic_1.Characteristic.RecordingAudioActive, false);
489
+ this.operatingModeService.updateCharacteristic(Characteristic_1.Characteristic.EventSnapshotsActive, true);
490
+ this.operatingModeService.updateCharacteristic(Characteristic_1.Characteristic.PeriodicSnapshotsActive, true);
491
+ this.operatingModeService.updateCharacteristic(Characteristic_1.Characteristic.HomeKitCameraActive, true);
492
+ try {
493
+ for (var _b = (0, tslib_1.__values)(this.sensorServices), _c = _b.next(); !_c.done; _c = _b.next()) {
494
+ var service = _c.value;
495
+ service.setCharacteristic(Characteristic_1.Characteristic.StatusActive, true);
496
+ }
497
+ }
498
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
499
+ finally {
500
+ try {
501
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
502
+ }
503
+ finally { if (e_4) throw e_4.error; }
504
+ }
505
+ try {
506
+ // notifying the delegate about the updated state
507
+ this.delegate.updateRecordingActive(false);
508
+ this.delegate.updateRecordingConfiguration(undefined);
509
+ }
510
+ catch (error) {
511
+ console.error("CameraRecordingDelegate failed to update state after handleFactoryReset: " + error.stack);
512
+ }
513
+ };
514
+ return RecordingManagement;
515
+ }());
516
+ exports.RecordingManagement = RecordingManagement;
517
+ var CameraRecordingStreamEvents;
518
+ (function (CameraRecordingStreamEvents) {
519
+ /**
520
+ * This event is fired when the recording stream is closed.
521
+ * Either due to a normal exit (e.g. the HomeKit Controller acknowledging the stream)
522
+ * or due to an erroneous exit (e.g. HDS connection getting closed).
523
+ */
524
+ CameraRecordingStreamEvents["CLOSED"] = "closed";
525
+ })(CameraRecordingStreamEvents || (CameraRecordingStreamEvents = {}));
526
+ /**
527
+ * A `CameraRecordingStream` represents an ongoing stream request for a HomeKit Secure Video recording.
528
+ * A single camera can only support one ongoing recording at a time.
529
+ */
530
+ var CameraRecordingStream = /** @class */ (function (_super) {
531
+ (0, tslib_1.__extends)(CameraRecordingStream, _super);
532
+ function CameraRecordingStream(connection, delegate, requestId, streamId) {
533
+ var _a;
534
+ var _this = _super.call(this) || this;
535
+ _this.closed = false;
536
+ _this.eventHandler = (_a = {},
537
+ _a["close" /* CLOSE */] = _this.handleDataSendClose.bind(_this),
538
+ _a["ack" /* ACK */] = _this.handleDataSendAck.bind(_this),
539
+ _a);
540
+ _this.requestHandler = undefined;
541
+ _this.connection = connection;
542
+ _this.delegate = delegate;
543
+ _this.hdsRequestId = requestId;
544
+ _this.streamId = streamId;
545
+ _this.connection.on("closed" /* CLOSED */, _this.closeListener = _this.handleDataStreamConnectionClosed.bind(_this));
546
+ _this.connection.addProtocolHandler("dataSend" /* DATA_SEND */, _this);
547
+ return _this;
548
+ }
549
+ CameraRecordingStream.prototype.startStreaming = function () {
550
+ // noinspection JSIgnoredPromiseFromCall
551
+ this._startStreaming();
552
+ };
553
+ CameraRecordingStream.prototype._startStreaming = function () {
554
+ var e_5, _a;
555
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
556
+ var maxChunk, initialization, dataSequenceNumber, lastFragmentWasMarkedLast, _b, _c, packet, fragment, offset, dataChunkSequenceNumber, data, event, e_5_1, error_1, closeReason;
557
+ return (0, tslib_1.__generator)(this, function (_d) {
558
+ switch (_d.label) {
559
+ case 0:
560
+ debug("[HDS %s] Sending DATA_SEND OPEN response for streamId %d", this.connection.remoteAddress, this.streamId);
561
+ this.connection.sendResponse("dataSend" /* DATA_SEND */, "open" /* OPEN */, this.hdsRequestId, datastream_1.HDSStatus.SUCCESS, {
562
+ status: datastream_1.HDSStatus.SUCCESS,
563
+ });
564
+ maxChunk = 0x40000;
565
+ initialization = true;
566
+ dataSequenceNumber = 1;
567
+ lastFragmentWasMarkedLast = false;
568
+ _d.label = 1;
569
+ case 1:
570
+ _d.trys.push([1, 14, 15, 16]);
571
+ this.generator = this.delegate.handleRecordingStreamRequest(this.streamId);
572
+ _d.label = 2;
573
+ case 2:
574
+ _d.trys.push([2, 7, 8, 13]);
575
+ _b = (0, tslib_1.__asyncValues)(this.generator);
576
+ _d.label = 3;
577
+ case 3: return [4 /*yield*/, _b.next()];
578
+ case 4:
579
+ if (!(_c = _d.sent(), !_c.done)) return [3 /*break*/, 6];
580
+ packet = _c.value;
581
+ if (this.closed) {
582
+ console.error("[HDS ".concat(this.connection.remoteAddress, "] Delegate yielded fragment after stream ").concat(this.streamId, " was already closed!"));
583
+ return [3 /*break*/, 6];
584
+ }
585
+ if (lastFragmentWasMarkedLast) {
586
+ console.error("[HDS ".concat(this.connection.remoteAddress, "] Delegate yielded fragment for stream ").concat(this.streamId, " after already signaling end of stream!"));
587
+ return [3 /*break*/, 6];
588
+ }
589
+ fragment = packet.data;
590
+ offset = 0;
591
+ dataChunkSequenceNumber = 1;
592
+ while (offset < fragment.length) {
593
+ data = fragment.slice(offset, offset + maxChunk);
594
+ offset += data.length;
595
+ event = {
596
+ streamId: this.streamId,
597
+ packets: [{
598
+ data: data,
599
+ metadata: {
600
+ dataType: initialization ? "mediaInitialization" /* MEDIA_INITIALIZATION */ : "mediaFragment" /* MEDIA_FRAGMENT */,
601
+ dataSequenceNumber: dataSequenceNumber,
602
+ dataChunkSequenceNumber: dataChunkSequenceNumber,
603
+ isLastDataChunk: offset >= fragment.length,
604
+ dataTotalSize: dataChunkSequenceNumber === 1 ? fragment.length : undefined,
605
+ },
606
+ }],
607
+ endOfStream: offset >= fragment.length ? Boolean(packet.isLast).valueOf() : undefined,
608
+ };
609
+ 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);
610
+ this.connection.sendEvent("dataSend" /* DATA_SEND */, "data" /* DATA */, event);
611
+ dataChunkSequenceNumber++;
612
+ initialization = false;
613
+ }
614
+ lastFragmentWasMarkedLast = packet.isLast;
615
+ if (packet.isLast) {
616
+ return [3 /*break*/, 6];
617
+ }
618
+ dataSequenceNumber++;
619
+ _d.label = 5;
620
+ case 5: return [3 /*break*/, 3];
621
+ case 6: return [3 /*break*/, 13];
622
+ case 7:
623
+ e_5_1 = _d.sent();
624
+ e_5 = { error: e_5_1 };
625
+ return [3 /*break*/, 13];
626
+ case 8:
627
+ _d.trys.push([8, , 11, 12]);
628
+ if (!(_c && !_c.done && (_a = _b.return))) return [3 /*break*/, 10];
629
+ return [4 /*yield*/, _a.call(_b)];
630
+ case 9:
631
+ _d.sent();
632
+ _d.label = 10;
633
+ case 10: return [3 /*break*/, 12];
634
+ case 11:
635
+ if (e_5) throw e_5.error;
636
+ return [7 /*endfinally*/];
637
+ case 12: return [7 /*endfinally*/];
638
+ case 13:
639
+ if (!lastFragmentWasMarkedLast && !this.closed) {
640
+ // Delegate violates the contract. Exited normally on a non-closed stream without properly setting `isLast`.
641
+ console.warn("[HDS ".concat(this.connection.remoteAddress, "] Delegate finished streaming for ").concat(this.streamId, " without setting RecordingPacket.isLast. Can't notify Controller about endOfStream!"));
642
+ }
643
+ return [3 /*break*/, 16];
644
+ case 14:
645
+ error_1 = _d.sent();
646
+ if (this.closed) {
647
+ console.warn("[HDS ".concat(this.connection.remoteAddress, "] Encountered unexpected error on already closed recording stream ").concat(this.streamId, ": ").concat(error_1.stack));
648
+ }
649
+ else {
650
+ closeReason = 5 /* UNEXPECTED_FAILURE */;
651
+ if (error_1 instanceof datastream_1.HDSProtocolError) {
652
+ closeReason = error_1.reason;
653
+ debug("[HDS %s] Delegate signaled to close the recording stream %d", this.connection.remoteAddress, this.streamId);
654
+ }
655
+ else {
656
+ console.error("[HDS ".concat(this.connection.remoteAddress, "] Encountered unexpected error for recording stream ").concat(this.streamId, ": ").concat(error_1.stack));
657
+ }
658
+ this.connection.sendEvent("dataSend" /* DATA_SEND */, "close" /* CLOSE */, {
659
+ streamId: this.streamId,
660
+ reason: closeReason,
661
+ });
662
+ }
663
+ return [2 /*return*/];
664
+ case 15:
665
+ this.generator = undefined;
666
+ if (this.generatorTimeout) {
667
+ clearTimeout(this.generatorTimeout);
668
+ }
669
+ return [7 /*endfinally*/];
670
+ case 16:
671
+ if (initialization) { // we never actually sent anything out there!
672
+ console.warn("[HDS ".concat(this.connection.remoteAddress, "] Delegate finished recording stream ").concat(this.streamId, " without sending anything out. Controller will CANCEL."));
673
+ }
674
+ debug("[HDS %s] Finished DATA_SEND transmission for stream %d!", this.connection.remoteAddress, this.streamId);
675
+ return [2 /*return*/];
676
+ }
677
+ });
678
+ });
679
+ };
680
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
681
+ CameraRecordingStream.prototype.handleDataSendAck = function (message) {
682
+ var _this = this;
683
+ var streamId = message.streamId;
684
+ var endOfStream = message.endOfStream;
685
+ // The HomeKit Controller will send a DATA_SEND ACK if we set the `endOfStream` flag in the last packet
686
+ // of our DATA_SEND DATA packet.
687
+ // To my testing the session is then considered complete and the HomeKit controller will close the HDS Connection after 5 seconds.
688
+ debug("[HDS %s] Received DATA_SEND ACK packet for streamId %s. Acknowledged %s.", this.connection.remoteAddress, streamId, endOfStream);
689
+ this.handleClosed(function () { var _a, _b; return (_b = (_a = _this.delegate).acknowledgeStream) === null || _b === void 0 ? void 0 : _b.call(_a, _this.streamId); });
690
+ };
691
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
692
+ CameraRecordingStream.prototype.handleDataSendClose = function (message) {
693
+ var _this = this;
694
+ // see https://github.com/Supereg/secure-video-specification#43-close
695
+ var streamId = message.streamId;
696
+ var reason = message.reason;
697
+ if (streamId !== this.streamId) {
698
+ return;
699
+ }
700
+ debug("[HDS %s] Received DATA_SEND CLOSE for streamId %d with reason %s",
701
+ // @ts-expect-error: forceConsistentCasingInFileNames compiler option
702
+ this.connection.remoteAddress, streamId, datastream_1.HDSProtocolSpecificErrorReason[reason]);
703
+ this.handleClosed(function () { return _this.delegate.closeRecordingStream(streamId, reason); });
704
+ };
705
+ CameraRecordingStream.prototype.handleDataStreamConnectionClosed = function () {
706
+ var _this = this;
707
+ debug("[HDS %s] The HDS connection of the stream %d closed.", this.connection.remoteAddress, this.streamId);
708
+ this.handleClosed(function () { return _this.delegate.closeRecordingStream(_this.streamId, undefined); });
709
+ };
710
+ CameraRecordingStream.prototype.handleClosed = function (closure) {
711
+ var _this = this;
712
+ this.closed = true;
713
+ this.connection.removeProtocolHandler("dataSend" /* DATA_SEND */, this);
714
+ this.connection.removeListener("closed" /* CLOSED */, this.closeListener);
715
+ if (this.generator) {
716
+ // when this variable is defined, the generator hasn't returned yet.
717
+ // we start a timeout to uncover potential programming mistakes where we await forever and can't free resources.
718
+ this.generatorTimeout = setTimeout(function () {
719
+ console.error("[HDS %s] Recording download stream %d is still awaiting generator although stream was closed 10s ago!", _this.connection.remoteAddress, _this.streamId);
720
+ }, 10000);
721
+ }
722
+ try {
723
+ closure();
724
+ }
725
+ catch (error) {
726
+ console.error("[HDS ".concat(this.connection.remoteAddress, "] CameraRecordingDelegated failed to handle closing the stream ").concat(this.streamId, ": ").concat(error.stack));
727
+ }
728
+ this.emit("closed" /* CLOSED */);
729
+ };
730
+ /**
731
+ * This method can be used to close a recording session from the outside.
732
+ * @param reason - The reason to close the stream with.
733
+ */
734
+ CameraRecordingStream.prototype.close = function (reason) {
735
+ var _this = this;
736
+ if (this.closed) {
737
+ return;
738
+ }
739
+ debug("[HDS %s] Recording stream %d was closed manually with reason %s.",
740
+ // @ts-expect-error: forceConsistentCasingInFileNames compiler option
741
+ this.connection.remoteAddress, this.streamId, datastream_1.HDSProtocolSpecificErrorReason[reason]);
742
+ this.connection.sendEvent("dataSend" /* DATA_SEND */, "close" /* CLOSE */, {
743
+ streamId: this.streamId,
744
+ reason: reason,
745
+ });
746
+ this.handleClosed(function () { return _this.delegate.closeRecordingStream(_this.streamId, reason); });
747
+ };
748
+ return CameraRecordingStream;
749
+ }(events_1.EventEmitter));
750
+ //# sourceMappingURL=RecordingManagement.js.map