hap-nodejs 1.0.0-beta.1 → 1.0.0-beta.3

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 (225) hide show
  1. package/@types/bonjour-hap.d.ts +4 -3
  2. package/@types/simple-plist.d.ts +2 -1
  3. package/README.md +2 -1
  4. package/dist/BridgedCore.js +6 -5
  5. package/dist/BridgedCore.js.map +1 -1
  6. package/dist/Core.js +12 -10
  7. package/dist/Core.js.map +1 -1
  8. package/dist/accessories/AirConditioner_accessory.js +27 -27
  9. package/dist/accessories/AirConditioner_accessory.js.map +1 -1
  10. package/dist/accessories/AppleTVRemote_accessory.js +17 -16
  11. package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
  12. package/dist/accessories/Camera_accessory.js +433 -45
  13. package/dist/accessories/Camera_accessory.js.map +1 -1
  14. package/dist/accessories/Fan_accessory.js +8 -13
  15. package/dist/accessories/Fan_accessory.js.map +1 -1
  16. package/dist/accessories/GarageDoorOpener_accessory.js +11 -12
  17. package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
  18. package/dist/accessories/Light-AdaptiveLighting_accessory.js +5 -6
  19. package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
  20. package/dist/accessories/Light_accessory.js +34 -25
  21. package/dist/accessories/Light_accessory.js.map +1 -1
  22. package/dist/accessories/Lock_accessory.js +11 -12
  23. package/dist/accessories/Lock_accessory.js.map +1 -1
  24. package/dist/accessories/MotionSensor_accessory.js +8 -9
  25. package/dist/accessories/MotionSensor_accessory.js.map +1 -1
  26. package/dist/accessories/Outlet_accessory.js +9 -10
  27. package/dist/accessories/Outlet_accessory.js.map +1 -1
  28. package/dist/accessories/SmartSpeaker_accessory.js +11 -11
  29. package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
  30. package/dist/accessories/Sprinkler_accessory.js +19 -20
  31. package/dist/accessories/Sprinkler_accessory.js.map +1 -1
  32. package/dist/accessories/TV_accessory.js +13 -14
  33. package/dist/accessories/TV_accessory.js.map +1 -1
  34. package/dist/accessories/TemperatureSensor_accessory.js +7 -8
  35. package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
  36. package/dist/accessories/Wi-FiRouter_accessory.d.ts +1 -1
  37. package/dist/accessories/Wi-FiRouter_accessory.d.ts.map +1 -1
  38. package/dist/accessories/Wi-FiRouter_accessory.js +9 -10
  39. package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
  40. package/dist/accessories/Wi-FiSatellite_accessory.d.ts +1 -1
  41. package/dist/accessories/Wi-FiSatellite_accessory.d.ts.map +1 -1
  42. package/dist/accessories/Wi-FiSatellite_accessory.js +8 -9
  43. package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
  44. package/dist/accessories/gstreamer-audioProducer.d.ts +2 -2
  45. package/dist/accessories/gstreamer-audioProducer.d.ts.map +1 -1
  46. package/dist/accessories/gstreamer-audioProducer.js +31 -32
  47. package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
  48. package/dist/index.d.ts +54 -25
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +34 -9
  51. package/dist/index.js.map +1 -1
  52. package/dist/internal-types.d.ts +65 -124
  53. package/dist/internal-types.d.ts.map +1 -1
  54. package/dist/internal-types.js +66 -5
  55. package/dist/internal-types.js.map +1 -1
  56. package/dist/lib/Accessory.d.ts +142 -37
  57. package/dist/lib/Accessory.d.ts.map +1 -1
  58. package/dist/lib/Accessory.js +539 -451
  59. package/dist/lib/Accessory.js.map +1 -1
  60. package/dist/lib/AccessoryLoader.d.ts +20 -8
  61. package/dist/lib/AccessoryLoader.d.ts.map +1 -1
  62. package/dist/lib/AccessoryLoader.js +115 -93
  63. package/dist/lib/AccessoryLoader.js.map +1 -1
  64. package/dist/lib/Advertiser.d.ts +99 -6
  65. package/dist/lib/Advertiser.d.ts.map +1 -1
  66. package/dist/lib/Advertiser.js +558 -21
  67. package/dist/lib/Advertiser.js.map +1 -1
  68. package/dist/lib/Bridge.d.ts +3 -1
  69. package/dist/lib/Bridge.d.ts.map +1 -1
  70. package/dist/lib/Bridge.js +2 -0
  71. package/dist/lib/Bridge.js.map +1 -1
  72. package/dist/lib/Characteristic.d.ts +918 -59
  73. package/dist/lib/Characteristic.d.ts.map +1 -1
  74. package/dist/lib/Characteristic.js +308 -257
  75. package/dist/lib/Characteristic.js.map +1 -1
  76. package/dist/lib/HAPServer.d.ts +114 -21
  77. package/dist/lib/HAPServer.d.ts.map +1 -1
  78. package/dist/lib/HAPServer.js +231 -230
  79. package/dist/lib/HAPServer.js.map +1 -1
  80. package/dist/lib/Service.d.ts +339 -15
  81. package/dist/lib/Service.d.ts.map +1 -1
  82. package/dist/lib/Service.js +59 -50
  83. package/dist/lib/Service.js.map +1 -1
  84. package/dist/lib/camera/Camera.d.ts +15 -6
  85. package/dist/lib/camera/Camera.d.ts.map +1 -1
  86. package/dist/lib/camera/Camera.js +6 -3
  87. package/dist/lib/camera/Camera.js.map +1 -1
  88. package/dist/lib/camera/RTPProxy.d.ts +24 -19
  89. package/dist/lib/camera/RTPProxy.d.ts.map +1 -1
  90. package/dist/lib/camera/RTPProxy.js +230 -207
  91. package/dist/lib/camera/RTPProxy.js.map +1 -1
  92. package/dist/lib/camera/RTPStreamManagement.d.ts +202 -43
  93. package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
  94. package/dist/lib/camera/RTPStreamManagement.js +303 -189
  95. package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
  96. package/dist/lib/camera/RecordingManagement.d.ts +326 -0
  97. package/dist/lib/camera/RecordingManagement.d.ts.map +1 -0
  98. package/dist/lib/camera/RecordingManagement.js +833 -0
  99. package/dist/lib/camera/RecordingManagement.js.map +1 -0
  100. package/dist/lib/camera/index.d.ts +4 -3
  101. package/dist/lib/camera/index.d.ts.map +1 -1
  102. package/dist/lib/camera/index.js +1 -0
  103. package/dist/lib/camera/index.js.map +1 -1
  104. package/dist/lib/controller/AdaptiveLightingController.d.ts +37 -11
  105. package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
  106. package/dist/lib/controller/AdaptiveLightingController.js +101 -86
  107. package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
  108. package/dist/lib/controller/CameraController.d.ts +290 -12
  109. package/dist/lib/controller/CameraController.d.ts.map +1 -1
  110. package/dist/lib/controller/CameraController.js +403 -47
  111. package/dist/lib/controller/CameraController.js.map +1 -1
  112. package/dist/lib/controller/Controller.d.ts +31 -10
  113. package/dist/lib/controller/Controller.d.ts.map +1 -1
  114. package/dist/lib/controller/Controller.js +7 -0
  115. package/dist/lib/controller/Controller.js.map +1 -1
  116. package/dist/lib/controller/DoorbellController.d.ts +47 -1
  117. package/dist/lib/controller/DoorbellController.d.ts.map +1 -1
  118. package/dist/lib/controller/DoorbellController.js +65 -11
  119. package/dist/lib/controller/DoorbellController.js.map +1 -1
  120. package/dist/lib/controller/RemoteController.d.ts +111 -42
  121. package/dist/lib/controller/RemoteController.d.ts.map +1 -1
  122. package/dist/lib/controller/RemoteController.js +228 -203
  123. package/dist/lib/controller/RemoteController.js.map +1 -1
  124. package/dist/lib/controller/index.d.ts +4 -4
  125. package/dist/lib/datastream/DataStreamManagement.d.ts +25 -19
  126. package/dist/lib/datastream/DataStreamManagement.d.ts.map +1 -1
  127. package/dist/lib/datastream/DataStreamManagement.js +42 -35
  128. package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
  129. package/dist/lib/datastream/DataStreamParser.d.ts +63 -24
  130. package/dist/lib/datastream/DataStreamParser.d.ts.map +1 -1
  131. package/dist/lib/datastream/DataStreamParser.js +132 -86
  132. package/dist/lib/datastream/DataStreamParser.js.map +1 -1
  133. package/dist/lib/datastream/DataStreamServer.d.ts +154 -50
  134. package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
  135. package/dist/lib/datastream/DataStreamServer.js +242 -147
  136. package/dist/lib/datastream/DataStreamServer.js.map +1 -1
  137. package/dist/lib/datastream/index.d.ts +3 -3
  138. package/dist/lib/definitions/CharacteristicDefinitions.d.ts +181 -0
  139. package/dist/lib/definitions/CharacteristicDefinitions.d.ts.map +1 -1
  140. package/dist/lib/definitions/CharacteristicDefinitions.js +968 -499
  141. package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
  142. package/dist/lib/definitions/ServiceDefinitions.d.ts +58 -0
  143. package/dist/lib/definitions/ServiceDefinitions.d.ts.map +1 -1
  144. package/dist/lib/definitions/ServiceDefinitions.js +173 -6
  145. package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
  146. package/dist/lib/definitions/generate-definitions.d.ts +1 -0
  147. package/dist/lib/definitions/generate-definitions.d.ts.map +1 -1
  148. package/dist/lib/definitions/generate-definitions.js +29 -21
  149. package/dist/lib/definitions/generate-definitions.js.map +1 -1
  150. package/dist/lib/definitions/generator-configuration.d.ts.map +1 -1
  151. package/dist/lib/definitions/generator-configuration.js +62 -29
  152. package/dist/lib/definitions/generator-configuration.js.map +1 -1
  153. package/dist/lib/model/AccessoryInfo.d.ts +16 -10
  154. package/dist/lib/model/AccessoryInfo.d.ts.map +1 -1
  155. package/dist/lib/model/AccessoryInfo.js +87 -73
  156. package/dist/lib/model/AccessoryInfo.js.map +1 -1
  157. package/dist/lib/model/ControllerStorage.d.ts +3 -0
  158. package/dist/lib/model/ControllerStorage.d.ts.map +1 -1
  159. package/dist/lib/model/ControllerStorage.js +7 -4
  160. package/dist/lib/model/ControllerStorage.js.map +1 -1
  161. package/dist/lib/model/HAPStorage.d.ts +3 -0
  162. package/dist/lib/model/HAPStorage.d.ts.map +1 -1
  163. package/dist/lib/model/HAPStorage.js +4 -0
  164. package/dist/lib/model/HAPStorage.js.map +1 -1
  165. package/dist/lib/model/IdentifierCache.d.ts +12 -11
  166. package/dist/lib/model/IdentifierCache.d.ts.map +1 -1
  167. package/dist/lib/model/IdentifierCache.js +68 -65
  168. package/dist/lib/model/IdentifierCache.js.map +1 -1
  169. package/dist/lib/tv/AccessControlManagement.d.ts +12 -1
  170. package/dist/lib/tv/AccessControlManagement.d.ts.map +1 -1
  171. package/dist/lib/tv/AccessControlManagement.js +13 -5
  172. package/dist/lib/tv/AccessControlManagement.js.map +1 -1
  173. package/dist/lib/util/clone.d.ts +2 -1
  174. package/dist/lib/util/clone.d.ts.map +1 -1
  175. package/dist/lib/util/clone.js +2 -0
  176. package/dist/lib/util/clone.js.map +1 -1
  177. package/dist/lib/util/color-utils.d.ts +4 -1
  178. package/dist/lib/util/color-utils.d.ts.map +1 -1
  179. package/dist/lib/util/color-utils.js +5 -2
  180. package/dist/lib/util/color-utils.js.map +1 -1
  181. package/dist/lib/util/eventedhttp.d.ts +62 -15
  182. package/dist/lib/util/eventedhttp.d.ts.map +1 -1
  183. package/dist/lib/util/eventedhttp.js +234 -171
  184. package/dist/lib/util/eventedhttp.js.map +1 -1
  185. package/dist/lib/util/hapCrypto.d.ts +35 -7
  186. package/dist/lib/util/hapCrypto.d.ts.map +1 -1
  187. package/dist/lib/util/hapCrypto.js +86 -78
  188. package/dist/lib/util/hapCrypto.js.map +1 -1
  189. package/dist/lib/util/hapStatusError.d.ts +2 -0
  190. package/dist/lib/util/hapStatusError.d.ts.map +1 -1
  191. package/dist/lib/util/hapStatusError.js +5 -3
  192. package/dist/lib/util/hapStatusError.js.map +1 -1
  193. package/dist/lib/util/net-utils.d.ts +7 -0
  194. package/dist/lib/util/net-utils.d.ts.map +1 -1
  195. package/dist/lib/util/net-utils.js +11 -4
  196. package/dist/lib/util/net-utils.js.map +1 -1
  197. package/dist/lib/util/once.d.ts +6 -1
  198. package/dist/lib/util/once.d.ts.map +1 -1
  199. package/dist/lib/util/once.js +9 -3
  200. package/dist/lib/util/once.js.map +1 -1
  201. package/dist/lib/util/promise-utils.d.ts +15 -0
  202. package/dist/lib/util/promise-utils.d.ts.map +1 -0
  203. package/dist/lib/util/promise-utils.js +36 -0
  204. package/dist/lib/util/promise-utils.js.map +1 -0
  205. package/dist/lib/util/request-util.d.ts +16 -0
  206. package/dist/lib/util/request-util.d.ts.map +1 -1
  207. package/dist/lib/util/request-util.js +43 -27
  208. package/dist/lib/util/request-util.js.map +1 -1
  209. package/dist/lib/util/time.d.ts +7 -1
  210. package/dist/lib/util/time.d.ts.map +1 -1
  211. package/dist/lib/util/time.js +13 -7
  212. package/dist/lib/util/time.js.map +1 -1
  213. package/dist/lib/util/tlv.d.ts +95 -5
  214. package/dist/lib/util/tlv.d.ts.map +1 -1
  215. package/dist/lib/util/tlv.js +96 -24
  216. package/dist/lib/util/tlv.js.map +1 -1
  217. package/dist/lib/util/uuid.d.ts +2 -3
  218. package/dist/lib/util/uuid.d.ts.map +1 -1
  219. package/dist/lib/util/uuid.js +25 -19
  220. package/dist/lib/util/uuid.js.map +1 -1
  221. package/dist/types.d.ts +271 -18
  222. package/dist/types.d.ts.map +1 -1
  223. package/dist/types.js +8 -0
  224. package/dist/types.js.map +1 -1
  225. package/package.json +28 -25
@@ -1,23 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- var __1 = require("..");
3
+ var tslib_1 = require("tslib");
4
+ var assert_1 = tslib_1.__importDefault(require("assert"));
4
5
  var child_process_1 = require("child_process");
5
- var cameraUUID = __1.uuid.generate('hap-nodejs:accessories:ip-camera');
6
- var camera = exports.accessory = new __1.Accessory('IPCamera', cameraUUID);
7
- // @ts-ignore
6
+ var events_1 = require("events");
7
+ var net_1 = require("net");
8
+ var __1 = require("..");
9
+ var cameraUUID = __1.uuid.generate("hap-nodejs:accessories:ip-camera");
10
+ var camera = exports.accessory = new __1.Accessory("IPCamera", cameraUUID);
11
+ // @ts-expect-error: Core/BridgeCore API
8
12
  camera.username = "9F:B2:46:0C:40:DB";
9
- // @ts-ignore
13
+ // @ts-expect-error: Core/BridgeCore API
10
14
  camera.pincode = "948-23-459";
11
- camera.category = 17 /* IP_CAMERA */;
15
+ camera.category = 17 /* Categories.IP_CAMERA */;
12
16
  var FFMPEGH264ProfileNames = [
13
17
  "baseline",
14
18
  "main",
15
- "high"
19
+ "high",
16
20
  ];
17
21
  var FFMPEGH264LevelNames = [
18
22
  "3.1",
19
23
  "3.2",
20
- "4.0"
24
+ "4.0",
21
25
  ];
22
26
  var ports = new Set();
23
27
  function getPort() {
@@ -34,25 +38,26 @@ var ExampleCamera = /** @class */ (function () {
34
38
  // keep track of sessions
35
39
  this.pendingSessions = {};
36
40
  this.ongoingSessions = {};
41
+ this.handlingStreamingRequest = false;
37
42
  }
38
43
  ExampleCamera.prototype.handleSnapshotRequest = function (request, callback) {
39
44
  var _this = this;
40
- var ffmpegCommand = "-f lavfi -i testsrc=s=" + request.width + "x" + request.height + " -vframes 1 -f mjpeg -";
41
- var ffmpeg = child_process_1.spawn("ffmpeg", ffmpegCommand.split(" "), { env: process.env });
45
+ var ffmpegCommand = "-f lavfi -i testsrc=s=".concat(request.width, "x").concat(request.height, " -vframes 1 -f mjpeg -");
46
+ var ffmpeg = (0, child_process_1.spawn)("ffmpeg", ffmpegCommand.split(" "), { env: process.env });
42
47
  var snapshotBuffers = [];
43
- ffmpeg.stdout.on('data', function (data) { return snapshotBuffers.push(data); });
44
- ffmpeg.stderr.on('data', function (data) {
48
+ ffmpeg.stdout.on("data", function (data) { return snapshotBuffers.push(data); });
49
+ ffmpeg.stderr.on("data", function (data) {
45
50
  if (_this.ffmpegDebugOutput) {
46
51
  console.log("SNAPSHOT: " + String(data));
47
52
  }
48
53
  });
49
- ffmpeg.on('exit', function (code, signal) {
54
+ ffmpeg.on("exit", function (code, signal) {
50
55
  if (signal) {
51
56
  console.log("Snapshot process was killed with signal: " + signal);
52
57
  callback(new Error("killed with signal " + signal));
53
58
  }
54
59
  else if (code === 0) {
55
- console.log("Successfully captured snapshot at " + request.width + "x" + request.height);
60
+ console.log("Successfully captured snapshot at ".concat(request.width, "x").concat(request.height));
56
61
  callback(undefined, Buffer.concat(snapshotBuffers));
57
62
  }
58
63
  else {
@@ -96,7 +101,7 @@ var ExampleCamera = /** @class */ (function () {
96
101
  var _this = this;
97
102
  var sessionId = request.sessionID;
98
103
  switch (request.type) {
99
- case "start" /* START */: {
104
+ case "start" /* StreamRequestTypes.START */: {
100
105
  var sessionInfo = this.pendingSessions[sessionId];
101
106
  var video = request.video;
102
107
  var profile = FFMPEGH264ProfileNames[video.profile];
@@ -106,6 +111,7 @@ var ExampleCamera = /** @class */ (function () {
106
111
  var fps = video.fps;
107
112
  var payloadType = video.pt;
108
113
  var maxBitrate = video.max_bit_rate;
114
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
109
115
  var rtcpInterval = video.rtcp_interval; // usually 0.5
110
116
  var mtu = video.mtu; // maximum transmission unit
111
117
  var address = sessionInfo.address;
@@ -114,30 +120,30 @@ var ExampleCamera = /** @class */ (function () {
114
120
  var ssrc = sessionInfo.videoSSRC;
115
121
  var cryptoSuite = sessionInfo.videoCryptoSuite;
116
122
  var videoSRTP = sessionInfo.videoSRTP.toString("base64");
117
- console.log("Starting video stream (" + width + "x" + height + ", " + fps + " fps, " + maxBitrate + " kbps, " + mtu + " mtu)...");
118
- var videoffmpegCommand = "-re -f lavfi -i testsrc=s=" + width + "x" + height + ":r=" + fps + " -map 0:0 " +
119
- ("-c:v h264 -pix_fmt yuv420p -r " + fps + " -an -sn -dn -b:v " + maxBitrate + "k ") +
120
- ("-profile:v " + profile + " -level:v " + level + " ") +
121
- ("-payload_type " + payloadType + " -ssrc " + ssrc + " -f rtp ");
122
- if (cryptoSuite !== 2 /* NONE */) {
123
+ console.log("Starting video stream (".concat(width, "x").concat(height, ", ").concat(fps, " fps, ").concat(maxBitrate, " kbps, ").concat(mtu, " mtu)..."));
124
+ var videoffmpegCommand = "-re -f lavfi -i testsrc=s=".concat(width, "x").concat(height, ":r=").concat(fps, " -map 0:0 ") +
125
+ "-c:v h264 -pix_fmt yuv420p -r ".concat(fps, " -an -sn -dn -b:v ").concat(maxBitrate, "k ") +
126
+ "-profile:v ".concat(profile, " -level:v ").concat(level, " ") +
127
+ "-payload_type ".concat(payloadType, " -ssrc ").concat(ssrc, " -f rtp ");
128
+ if (cryptoSuite !== 2 /* SRTPCryptoSuites.NONE */) {
123
129
  var suite = void 0;
124
130
  switch (cryptoSuite) {
125
- case 0 /* AES_CM_128_HMAC_SHA1_80 */: // actually ffmpeg just supports AES_CM_128_HMAC_SHA1_80
131
+ case 0 /* SRTPCryptoSuites.AES_CM_128_HMAC_SHA1_80 */: // actually ffmpeg just supports AES_CM_128_HMAC_SHA1_80
126
132
  suite = "AES_CM_128_HMAC_SHA1_80";
127
133
  break;
128
- case 1 /* AES_CM_256_HMAC_SHA1_80 */:
134
+ case 1 /* SRTPCryptoSuites.AES_CM_256_HMAC_SHA1_80 */:
129
135
  suite = "AES_CM_256_HMAC_SHA1_80";
130
136
  break;
131
137
  }
132
- videoffmpegCommand += "-srtp_out_suite " + suite + " -srtp_out_params " + videoSRTP + " s";
138
+ videoffmpegCommand += "-srtp_out_suite ".concat(suite, " -srtp_out_params ").concat(videoSRTP, " s");
133
139
  }
134
- videoffmpegCommand += "rtp://" + address + ":" + videoPort + "?rtcpport=" + videoPort + "&localrtcpport=" + localVideoPort + "&pkt_size=" + mtu;
140
+ videoffmpegCommand += "rtp://".concat(address, ":").concat(videoPort, "?rtcpport=").concat(videoPort, "&localrtcpport=").concat(localVideoPort, "&pkt_size=").concat(mtu);
135
141
  if (this.ffmpegDebugOutput) {
136
142
  console.log("FFMPEG command: ffmpeg " + videoffmpegCommand);
137
143
  }
138
- var ffmpegVideo = child_process_1.spawn('ffmpeg', videoffmpegCommand.split(' '), { env: process.env });
144
+ var ffmpegVideo = (0, child_process_1.spawn)("ffmpeg", videoffmpegCommand.split(" "), { env: process.env });
139
145
  var started_1 = false;
140
- ffmpegVideo.stderr.on('data', function (data) {
146
+ ffmpegVideo.stderr.on("data", function (data) {
141
147
  console.log(data.toString("utf8"));
142
148
  if (!started_1) {
143
149
  started_1 = true;
@@ -148,11 +154,11 @@ var ExampleCamera = /** @class */ (function () {
148
154
  console.log("VIDEO: " + String(data));
149
155
  }
150
156
  });
151
- ffmpegVideo.on('error', function (error) {
157
+ ffmpegVideo.on("error", function (error) {
152
158
  console.log("[Video] Failed to start video stream: " + error.message);
153
159
  callback(new Error("ffmpeg process creation failed!"));
154
160
  });
155
- ffmpegVideo.on('exit', function (code, signal) {
161
+ ffmpegVideo.on("exit", function (code, signal) {
156
162
  var message = "[Video] ffmpeg exited with code: " + code + " and signal: " + signal;
157
163
  if (code == null || code === 255) {
158
164
  console.log(message + " (Video stream stopped!)");
@@ -174,16 +180,20 @@ var ExampleCamera = /** @class */ (function () {
174
180
  delete this.pendingSessions[sessionId];
175
181
  break;
176
182
  }
177
- case "reconfigure" /* RECONFIGURE */:
183
+ case "reconfigure" /* StreamRequestTypes.RECONFIGURE */:
178
184
  // not supported by this example
179
185
  console.log("Received (unsupported) request to reconfigure to: " + JSON.stringify(request.video));
180
186
  callback();
181
187
  break;
182
- case "stop" /* STOP */:
188
+ case "stop" /* StreamRequestTypes.STOP */: {
183
189
  var ongoingSession = this.ongoingSessions[sessionId];
190
+ if (!ongoingSession) {
191
+ callback();
192
+ break;
193
+ }
184
194
  ports.delete(ongoingSession.localVideoPort);
185
195
  try {
186
- ongoingSession.process.kill('SIGKILL');
196
+ ongoingSession.process.kill("SIGKILL");
187
197
  }
188
198
  catch (e) {
189
199
  console.log("Error occurred terminating the video process!");
@@ -193,21 +203,350 @@ var ExampleCamera = /** @class */ (function () {
193
203
  console.log("Stopped streaming session!");
194
204
  callback();
195
205
  break;
206
+ }
196
207
  }
197
208
  };
209
+ ExampleCamera.prototype.updateRecordingActive = function (active) {
210
+ // we haven't implemented a prebuffer
211
+ console.log("Recording active set to " + active);
212
+ };
213
+ ExampleCamera.prototype.updateRecordingConfiguration = function (configuration) {
214
+ this.configuration = configuration;
215
+ console.log(configuration);
216
+ };
217
+ /**
218
+ * This is a very minimal, very experimental example on how to implement fmp4 streaming with a
219
+ * CameraController supporting HomeKit Secure Video.
220
+ *
221
+ * An ideal implementation would diverge from this in the following ways:
222
+ * * It would implement a prebuffer and respect the recording `active` characteristic for that.
223
+ * * It would start to immediately record after a trigger event occurred and not just
224
+ * when the HomeKit Controller requests it (see the documentation of `CameraRecordingDelegate`).
225
+ */
226
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
227
+ ExampleCamera.prototype.handleRecordingStreamRequest = function (streamId) {
228
+ var _a, _b, _c;
229
+ return tslib_1.__asyncGenerator(this, arguments, function handleRecordingStreamRequest_1() {
230
+ var STOP_AFTER_MOTION_STOP, profile, level, videoArgs, samplerate, audioArgs, pending, _d, _e, _f, box, motionDetected, fragment, isLast, e_1_1, error_1;
231
+ var _g, e_1, _h, _j;
232
+ return tslib_1.__generator(this, function (_k) {
233
+ switch (_k.label) {
234
+ case 0:
235
+ (0, assert_1.default)(!!this.configuration);
236
+ STOP_AFTER_MOTION_STOP = false;
237
+ this.handlingStreamingRequest = true;
238
+ (0, assert_1.default)(this.configuration.videoCodec.type === 0 /* VideoCodecType.H264 */);
239
+ profile = this.configuration.videoCodec.parameters.profile === 2 /* H264Profile.HIGH */ ? "high"
240
+ : this.configuration.videoCodec.parameters.profile === 1 /* H264Profile.MAIN */ ? "main" : "baseline";
241
+ level = this.configuration.videoCodec.parameters.level === 2 /* H264Level.LEVEL4_0 */ ? "4.0"
242
+ : this.configuration.videoCodec.parameters.level === 1 /* H264Level.LEVEL3_2 */ ? "3.2" : "3.1";
243
+ videoArgs = [
244
+ "-an",
245
+ "-sn",
246
+ "-dn",
247
+ "-codec:v",
248
+ "libx264",
249
+ "-pix_fmt",
250
+ "yuv420p",
251
+ "-profile:v", profile,
252
+ "-level:v", level,
253
+ "-b:v",
254
+ "".concat(this.configuration.videoCodec.parameters.bitRate, "k"),
255
+ "-force_key_frames",
256
+ "expr:eq(t,n_forced*".concat(this.configuration.videoCodec.parameters.iFrameInterval / 1000, ")"),
257
+ "-r", this.configuration.videoCodec.resolution[2].toString(),
258
+ ];
259
+ switch (this.configuration.audioCodec.samplerate) {
260
+ case 0 /* AudioRecordingSamplerate.KHZ_8 */:
261
+ samplerate = "8";
262
+ break;
263
+ case 1 /* AudioRecordingSamplerate.KHZ_16 */:
264
+ samplerate = "16";
265
+ break;
266
+ case 2 /* AudioRecordingSamplerate.KHZ_24 */:
267
+ samplerate = "24";
268
+ break;
269
+ case 3 /* AudioRecordingSamplerate.KHZ_32 */:
270
+ samplerate = "32";
271
+ break;
272
+ case 4 /* AudioRecordingSamplerate.KHZ_44_1 */:
273
+ samplerate = "44.1";
274
+ break;
275
+ case 5 /* AudioRecordingSamplerate.KHZ_48 */:
276
+ samplerate = "48";
277
+ break;
278
+ default:
279
+ throw new Error("Unsupported audio samplerate: " + this.configuration.audioCodec.samplerate);
280
+ }
281
+ audioArgs = ((_b = (_a = this.controller) === null || _a === void 0 ? void 0 : _a.recordingManagement) === null || _b === void 0 ? void 0 : _b.recordingManagementService.getCharacteristic(__1.Characteristic.RecordingAudioActive))
282
+ ? tslib_1.__spreadArray(tslib_1.__spreadArray([
283
+ "-acodec", "libfdk_aac"
284
+ ], tslib_1.__read((this.configuration.audioCodec.type === 0 /* AudioRecordingCodecType.AAC_LC */ ?
285
+ ["-profile:a", "aac_low"] :
286
+ ["-profile:a", "aac_eld"])), false), [
287
+ "-ar",
288
+ "".concat(samplerate, "k"),
289
+ "-b:a",
290
+ "".concat(this.configuration.audioCodec.bitrate, "k"),
291
+ "-ac",
292
+ "".concat(this.configuration.audioCodec.audioChannels),
293
+ ], false) : [];
294
+ this.server = new MP4StreamingServer("ffmpeg", "-f lavfi -i testsrc=s=".concat(this.configuration.videoCodec.resolution[0], "x").concat(this.configuration.videoCodec.resolution[1], ":r=").concat(this.configuration.videoCodec.resolution[2])
295
+ .split(/ /g), audioArgs, videoArgs);
296
+ return [4 /*yield*/, tslib_1.__await(this.server.start())];
297
+ case 1:
298
+ _k.sent();
299
+ if (!(!this.server || this.server.destroyed)) return [3 /*break*/, 3];
300
+ return [4 /*yield*/, tslib_1.__await(void 0)];
301
+ case 2: return [2 /*return*/, _k.sent()]; // early exit
302
+ case 3:
303
+ pending = [];
304
+ _k.label = 4;
305
+ case 4:
306
+ _k.trys.push([4, 22, , 23]);
307
+ _k.label = 5;
308
+ case 5:
309
+ _k.trys.push([5, 15, 16, 21]);
310
+ _d = true, _e = tslib_1.__asyncValues(this.server.generator());
311
+ _k.label = 6;
312
+ case 6: return [4 /*yield*/, tslib_1.__await(_e.next())];
313
+ case 7:
314
+ if (!(_f = _k.sent(), _g = _f.done, !_g)) return [3 /*break*/, 14];
315
+ _j = _f.value;
316
+ _d = false;
317
+ _k.label = 8;
318
+ case 8:
319
+ _k.trys.push([8, , 12, 13]);
320
+ box = _j;
321
+ pending.push(box.header, box.data);
322
+ motionDetected = (_c = camera.getService(__1.Service.MotionSensor)) === null || _c === void 0 ? void 0 : _c.getCharacteristic(__1.Characteristic.MotionDetected).value;
323
+ console.log("mp4 box type " + box.type + " and length " + box.length);
324
+ if (!(box.type === "moov" || box.type === "mdat")) return [3 /*break*/, 11];
325
+ fragment = Buffer.concat(pending);
326
+ pending.splice(0, pending.length);
327
+ isLast = STOP_AFTER_MOTION_STOP && !motionDetected;
328
+ return [4 /*yield*/, tslib_1.__await({
329
+ data: fragment,
330
+ isLast: isLast,
331
+ })];
332
+ case 9: return [4 /*yield*/, _k.sent()];
333
+ case 10:
334
+ _k.sent();
335
+ if (isLast) {
336
+ console.log("Ending session due to motion stopped!");
337
+ return [3 /*break*/, 14];
338
+ }
339
+ _k.label = 11;
340
+ case 11: return [3 /*break*/, 13];
341
+ case 12:
342
+ _d = true;
343
+ return [7 /*endfinally*/];
344
+ case 13: return [3 /*break*/, 6];
345
+ case 14: return [3 /*break*/, 21];
346
+ case 15:
347
+ e_1_1 = _k.sent();
348
+ e_1 = { error: e_1_1 };
349
+ return [3 /*break*/, 21];
350
+ case 16:
351
+ _k.trys.push([16, , 19, 20]);
352
+ if (!(!_d && !_g && (_h = _e.return))) return [3 /*break*/, 18];
353
+ return [4 /*yield*/, tslib_1.__await(_h.call(_e))];
354
+ case 17:
355
+ _k.sent();
356
+ _k.label = 18;
357
+ case 18: return [3 /*break*/, 20];
358
+ case 19:
359
+ if (e_1) throw e_1.error;
360
+ return [7 /*endfinally*/];
361
+ case 20: return [7 /*endfinally*/];
362
+ case 21: return [3 /*break*/, 23];
363
+ case 22:
364
+ error_1 = _k.sent();
365
+ if (!error_1.message.startsWith("FFMPEG")) { // cheap way of identifying our own emitted errors
366
+ console.error("Encountered unexpected error on generator " + error_1.stack);
367
+ }
368
+ return [3 /*break*/, 23];
369
+ case 23: return [2 /*return*/];
370
+ }
371
+ });
372
+ });
373
+ };
374
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
375
+ ExampleCamera.prototype.closeRecordingStream = function (streamId, reason) {
376
+ if (this.server) {
377
+ this.server.destroy();
378
+ this.server = undefined;
379
+ }
380
+ this.handlingStreamingRequest = false;
381
+ };
382
+ ExampleCamera.prototype.acknowledgeStream = function (streamId) {
383
+ this.closeRecordingStream(streamId);
384
+ };
198
385
  return ExampleCamera;
199
386
  }());
387
+ var MP4StreamingServer = /** @class */ (function () {
388
+ function MP4StreamingServer(ffmpegPath, ffmpegInput, audioOutputArgs, videoOutputArgs) {
389
+ var _a, _b, _c;
390
+ var _this = this;
391
+ /**
392
+ * This can be configured to output ffmpeg debug output!
393
+ */
394
+ this.debugMode = false;
395
+ this.destroyed = false;
396
+ this.connectPromise = new Promise(function (resolve) { return _this.connectResolve = resolve; });
397
+ this.server = (0, net_1.createServer)(this.handleConnection.bind(this));
398
+ this.ffmpegPath = ffmpegPath;
399
+ this.args = [];
400
+ (_a = this.args).push.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(ffmpegInput), false));
401
+ (_b = this.args).push.apply(_b, tslib_1.__spreadArray([], tslib_1.__read(audioOutputArgs), false));
402
+ this.args.push("-f", "mp4");
403
+ (_c = this.args).push.apply(_c, tslib_1.__spreadArray([], tslib_1.__read(videoOutputArgs), false));
404
+ this.args.push("-fflags", "+genpts", "-reset_timestamps", "1");
405
+ this.args.push("-movflags", "frag_keyframe+empty_moov+default_base_moof");
406
+ }
407
+ MP4StreamingServer.prototype.start = function () {
408
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
409
+ var promise, port;
410
+ return tslib_1.__generator(this, function (_a) {
411
+ switch (_a.label) {
412
+ case 0:
413
+ promise = (0, events_1.once)(this.server, "listening");
414
+ this.server.listen(); // listen on random port
415
+ return [4 /*yield*/, promise];
416
+ case 1:
417
+ _a.sent();
418
+ if (this.destroyed) {
419
+ return [2 /*return*/];
420
+ }
421
+ port = this.server.address().port;
422
+ this.args.push("tcp://127.0.0.1:" + port);
423
+ console.log(this.ffmpegPath + " " + this.args.join(" "));
424
+ this.childProcess = (0, child_process_1.spawn)(this.ffmpegPath, this.args, { env: process.env, stdio: this.debugMode ? "pipe" : "ignore" });
425
+ if (!this.childProcess) {
426
+ console.error("ChildProcess is undefined directly after the init!");
427
+ }
428
+ if (this.debugMode) {
429
+ this.childProcess.stdout.on("data", function (data) { return console.log(data.toString()); });
430
+ this.childProcess.stderr.on("data", function (data) { return console.log(data.toString()); });
431
+ }
432
+ return [2 /*return*/];
433
+ }
434
+ });
435
+ });
436
+ };
437
+ MP4StreamingServer.prototype.destroy = function () {
438
+ var _a, _b;
439
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.destroy();
440
+ (_b = this.childProcess) === null || _b === void 0 ? void 0 : _b.kill();
441
+ this.socket = undefined;
442
+ this.childProcess = undefined;
443
+ this.destroyed = true;
444
+ };
445
+ MP4StreamingServer.prototype.handleConnection = function (socket) {
446
+ var _a;
447
+ this.server.close(); // don't accept any further clients
448
+ this.socket = socket;
449
+ (_a = this.connectResolve) === null || _a === void 0 ? void 0 : _a.call(this);
450
+ };
451
+ /**
452
+ * Generator for `MP4Atom`s.
453
+ * Throws error to signal EOF when socket is closed.
454
+ */
455
+ MP4StreamingServer.prototype.generator = function () {
456
+ return tslib_1.__asyncGenerator(this, arguments, function generator_1() {
457
+ var header, length, type, data;
458
+ return tslib_1.__generator(this, function (_a) {
459
+ switch (_a.label) {
460
+ case 0: return [4 /*yield*/, tslib_1.__await(this.connectPromise)];
461
+ case 1:
462
+ _a.sent();
463
+ if (!this.socket || !this.childProcess) {
464
+ console.log("Socket undefined " + !!this.socket + " childProcess undefined " + !!this.childProcess);
465
+ throw new Error("Unexpected state!");
466
+ }
467
+ _a.label = 2;
468
+ case 2:
469
+ if (!true) return [3 /*break*/, 7];
470
+ return [4 /*yield*/, tslib_1.__await(this.read(8))];
471
+ case 3:
472
+ header = _a.sent();
473
+ length = header.readInt32BE(0) - 8;
474
+ type = header.slice(4).toString();
475
+ return [4 /*yield*/, tslib_1.__await(this.read(length))];
476
+ case 4:
477
+ data = _a.sent();
478
+ return [4 /*yield*/, tslib_1.__await({
479
+ header: header,
480
+ length: length,
481
+ type: type,
482
+ data: data,
483
+ })];
484
+ case 5: return [4 /*yield*/, _a.sent()];
485
+ case 6:
486
+ _a.sent();
487
+ return [3 /*break*/, 2];
488
+ case 7: return [2 /*return*/];
489
+ }
490
+ });
491
+ });
492
+ };
493
+ MP4StreamingServer.prototype.read = function (length) {
494
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
495
+ var value;
496
+ var _this = this;
497
+ return tslib_1.__generator(this, function (_a) {
498
+ if (!this.socket) {
499
+ throw Error("FFMPEG tried reading from closed socket!");
500
+ }
501
+ if (!length) {
502
+ return [2 /*return*/, Buffer.alloc(0)];
503
+ }
504
+ value = this.socket.read(length);
505
+ if (value) {
506
+ return [2 /*return*/, value];
507
+ }
508
+ return [2 /*return*/, new Promise(function (resolve, reject) {
509
+ var readHandler = function () {
510
+ var value = _this.socket.read(length);
511
+ if (value) {
512
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
513
+ cleanup();
514
+ resolve(value);
515
+ }
516
+ };
517
+ var endHandler = function () {
518
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
519
+ cleanup();
520
+ reject(new Error("FFMPEG socket closed during read for ".concat(length, " bytes!")));
521
+ };
522
+ var cleanup = function () {
523
+ var _a, _b;
524
+ (_a = _this.socket) === null || _a === void 0 ? void 0 : _a.removeListener("readable", readHandler);
525
+ (_b = _this.socket) === null || _b === void 0 ? void 0 : _b.removeListener("close", endHandler);
526
+ };
527
+ if (!_this.socket) {
528
+ throw new Error("FFMPEG socket is closed now!");
529
+ }
530
+ _this.socket.on("readable", readHandler);
531
+ _this.socket.on("close", endHandler);
532
+ })];
533
+ });
534
+ });
535
+ };
536
+ return MP4StreamingServer;
537
+ }());
200
538
  var streamDelegate = new ExampleCamera();
201
539
  var cameraController = new __1.CameraController({
202
540
  cameraStreamCount: 2,
203
541
  delegate: streamDelegate,
204
542
  streamingOptions: {
205
543
  // srtp: true, // legacy option which will just enable AES_CM_128_HMAC_SHA1_80 (can still be used though)
206
- supportedCryptoSuites: [2 /* NONE */, 0 /* AES_CM_128_HMAC_SHA1_80 */],
544
+ // NONE is not supported by iOS just there for testing with Wireshark for example
545
+ supportedCryptoSuites: [2 /* SRTPCryptoSuites.NONE */, 0 /* SRTPCryptoSuites.AES_CM_128_HMAC_SHA1_80 */],
207
546
  video: {
208
547
  codec: {
209
- profiles: [0 /* BASELINE */, 1 /* MAIN */, 2 /* HIGH */],
210
- levels: [0 /* LEVEL3_1 */, 1 /* LEVEL3_2 */, 2 /* LEVEL4_0 */],
548
+ profiles: [0 /* H264Profile.BASELINE */, 1 /* H264Profile.MAIN */, 2 /* H264Profile.HIGH */],
549
+ levels: [0 /* H264Level.LEVEL3_1 */, 1 /* H264Level.LEVEL3_2 */, 2 /* H264Level.LEVEL4_0 */],
211
550
  },
212
551
  resolutions: [
213
552
  [1920, 1080, 30],
@@ -224,19 +563,68 @@ var cameraController = new __1.CameraController({
224
563
  ],
225
564
  },
226
565
  /* audio option is omitted, as it is not supported in this example; HAP-NodeJS will fake an appropriate audio codec
227
- audio: {
228
- comfort_noise: false, // optional, default false
229
- codecs: [
230
- {
231
- type: AudioStreamingCodecType.OPUS,
232
- audioChannels: 1, // optional, default 1
233
- samplerate: [AudioStreamingSamplerate.KHZ_16, AudioStreamingSamplerate.KHZ_24], // 16 and 24 must be present for AAC-ELD or OPUS
566
+ audio: {
567
+ comfort_noise: false, // optional, default false
568
+ codecs: [
569
+ {
570
+ type: AudioStreamingCodecType.OPUS,
571
+ audioChannels: 1, // optional, default 1
572
+ samplerate: [AudioStreamingSamplerate.KHZ_16, AudioStreamingSamplerate.KHZ_24], // 16 and 24 must be present for AAC-ELD or OPUS
573
+ },
574
+ ],
575
+ },
576
+ // */
577
+ },
578
+ recording: {
579
+ options: {
580
+ prebufferLength: 4000,
581
+ mediaContainerConfiguration: {
582
+ type: 0 /* MediaContainerType.FRAGMENTED_MP4 */,
583
+ fragmentLength: 4000,
584
+ },
585
+ video: {
586
+ type: 0 /* VideoCodecType.H264 */,
587
+ parameters: {
588
+ profiles: [2 /* H264Profile.HIGH */],
589
+ levels: [2 /* H264Level.LEVEL4_0 */],
234
590
  },
235
- ],
591
+ resolutions: [
592
+ [320, 180, 30],
593
+ [320, 240, 15],
594
+ [320, 240, 30],
595
+ [480, 270, 30],
596
+ [480, 360, 30],
597
+ [640, 360, 30],
598
+ [640, 480, 30],
599
+ [1280, 720, 30],
600
+ [1280, 960, 30],
601
+ [1920, 1080, 30],
602
+ [1600, 1200, 30],
603
+ ],
604
+ },
605
+ audio: {
606
+ codecs: {
607
+ type: 1 /* AudioRecordingCodecType.AAC_ELD */,
608
+ audioChannels: 1,
609
+ samplerate: 5 /* AudioRecordingSamplerate.KHZ_48 */,
610
+ bitrateMode: 0 /* AudioBitrate.VARIABLE */,
611
+ },
612
+ },
236
613
  },
237
- // */
238
- }
614
+ delegate: streamDelegate,
615
+ },
616
+ sensors: {
617
+ motion: true,
618
+ occupancy: true,
619
+ },
239
620
  });
240
621
  streamDelegate.controller = cameraController;
241
622
  camera.configureController(cameraController);
623
+ // a service to trigger the motion sensor!
624
+ camera.addService(__1.Service.Switch, "MOTION TRIGGER")
625
+ .getCharacteristic(__1.Characteristic.On)
626
+ .onSet(function (value) {
627
+ var _a;
628
+ (_a = camera.getService(__1.Service.MotionSensor)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(__1.Characteristic.MotionDetected, value);
629
+ });
242
630
  //# sourceMappingURL=Camera_accessory.js.map