hap-nodejs 0.12.3-beta.26 → 0.12.3-beta.28
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/README.md +0 -1
- package/dist/BridgedCore.js +19 -18
- package/dist/BridgedCore.js.map +1 -1
- package/dist/Core.js +20 -17
- package/dist/Core.js.map +1 -1
- package/dist/accessories/AirConditioner_accessory.js +24 -24
- package/dist/accessories/AirConditioner_accessory.js.map +1 -1
- package/dist/accessories/AppleTVRemote_accessory.js +23 -23
- package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
- package/dist/accessories/Camera_accessory.js +373 -292
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +21 -15
- package/dist/accessories/Fan_accessory.js.map +1 -1
- package/dist/accessories/GarageDoorOpener_accessory.js +12 -12
- package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
- package/dist/accessories/Light-AdaptiveLighting_accessory.js +21 -31
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +48 -45
- package/dist/accessories/Light_accessory.js.map +1 -1
- package/dist/accessories/Lock_accessory.js +11 -11
- package/dist/accessories/Lock_accessory.js.map +1 -1
- package/dist/accessories/MotionSensor_accessory.js +8 -8
- package/dist/accessories/MotionSensor_accessory.js.map +1 -1
- package/dist/accessories/Outlet_accessory.js +10 -10
- package/dist/accessories/Outlet_accessory.js.map +1 -1
- package/dist/accessories/SmartSpeaker_accessory.js +11 -11
- package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
- package/dist/accessories/Sprinkler_accessory.js +19 -19
- package/dist/accessories/Sprinkler_accessory.js.map +1 -1
- package/dist/accessories/TV_accessory.js +17 -17
- package/dist/accessories/TV_accessory.js.map +1 -1
- package/dist/accessories/TemperatureSensor_accessory.js +6 -6
- package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.js +3 -3
- package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.js +4 -4
- package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.js +47 -36
- package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
- package/dist/accessories/types.js +2 -2
- package/dist/accessories/types.js.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +1088 -780
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/AccessoryLoader.js +40 -40
- package/dist/lib/AccessoryLoader.js.map +1 -1
- package/dist/lib/Advertiser.js +524 -392
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.js +10 -6
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.d.ts.map +1 -1
- package/dist/lib/Characteristic.js +539 -1510
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.js +265 -215
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.d.ts.map +1 -1
- package/dist/lib/Service.js +320 -519
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/Camera.js +14 -14
- package/dist/lib/camera/Camera.js.map +1 -1
- package/dist/lib/camera/RTPProxy.js +104 -112
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +257 -286
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +384 -319
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.js +1 -1
- package/dist/lib/controller/AdaptiveLightingController.d.ts +3 -19
- package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +218 -217
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.js +250 -191
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/DoorbellController.d.ts +1 -1
- package/dist/lib/controller/DoorbellController.js +40 -39
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.js +401 -343
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.js +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +57 -56
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +304 -259
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +269 -252
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.js +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +2858 -2089
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +1096 -864
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +679 -383
- package/dist/lib/definitions/generate-definitions.js.map +1 -1
- package/dist/lib/definitions/generator-configuration.js +29 -29
- package/dist/lib/definitions/generator-configuration.js.map +1 -1
- package/dist/lib/definitions/index.js +1 -1
- package/dist/lib/model/AccessoryInfo.js +136 -101
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.js +89 -86
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.js +16 -15
- package/dist/lib/model/HAPStorage.js.map +1 -1
- package/dist/lib/model/IdentifierCache.js +49 -49
- package/dist/lib/model/IdentifierCache.js.map +1 -1
- package/dist/lib/tv/AccessControlManagement.js +44 -40
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/clone.js +27 -5
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.js +12 -8
- package/dist/lib/util/color-utils.js.map +1 -1
- package/dist/lib/util/eventedhttp.d.ts.map +1 -1
- package/dist/lib/util/eventedhttp.js +409 -301
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.js +32 -31
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.js +12 -9
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.js +53 -32
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.js +8 -3
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.js +13 -8
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.js +3 -2
- package/dist/lib/util/request-util.js.map +1 -1
- package/dist/lib/util/time.js +5 -5
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/tlv.js +75 -57
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.js +19 -15
- package/dist/lib/util/uuid.js.map +1 -1
- package/package.json +16 -16
- package/dist/lib/util/checkName.d.ts +0 -8
- package/dist/lib/util/checkName.d.ts.map +0 -1
- package/dist/lib/util/checkName.js +0 -17
- package/dist/lib/util/checkName.js.map +0 -1
|
@@ -1,64 +1,63 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
var tslib_1 = require("tslib");
|
|
4
|
+
var assert_1 = tslib_1.__importDefault(require("assert"));
|
|
5
|
+
var child_process_1 = require("child_process");
|
|
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
11
|
// @ts-expect-error: Core/BridgeCore API
|
|
12
12
|
camera.username = "9F:B2:46:0C:40:DB";
|
|
13
13
|
// @ts-expect-error: Core/BridgeCore API
|
|
14
14
|
camera.pincode = "948-23-459";
|
|
15
15
|
camera.category = 17 /* Categories.IP_CAMERA */;
|
|
16
|
-
|
|
16
|
+
var FFMPEGH264ProfileNames = [
|
|
17
17
|
"baseline",
|
|
18
18
|
"main",
|
|
19
19
|
"high",
|
|
20
20
|
];
|
|
21
|
-
|
|
21
|
+
var FFMPEGH264LevelNames = [
|
|
22
22
|
"3.1",
|
|
23
23
|
"3.2",
|
|
24
24
|
"4.0",
|
|
25
25
|
];
|
|
26
|
-
|
|
26
|
+
var ports = new Set();
|
|
27
27
|
function getPort() {
|
|
28
|
-
for (
|
|
28
|
+
for (var i = 5011;; i++) {
|
|
29
29
|
if (!ports.has(i)) {
|
|
30
30
|
ports.add(i);
|
|
31
31
|
return i;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
ffmpeg.
|
|
50
|
-
|
|
51
|
-
if (this.ffmpegDebugOutput) {
|
|
35
|
+
var ExampleCamera = /** @class */ (function () {
|
|
36
|
+
function ExampleCamera() {
|
|
37
|
+
this.ffmpegDebugOutput = false;
|
|
38
|
+
// keep track of sessions
|
|
39
|
+
this.pendingSessions = {};
|
|
40
|
+
this.ongoingSessions = {};
|
|
41
|
+
this.handlingStreamingRequest = false;
|
|
42
|
+
}
|
|
43
|
+
ExampleCamera.prototype.handleSnapshotRequest = function (request, callback) {
|
|
44
|
+
var _this = this;
|
|
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 });
|
|
47
|
+
var snapshotBuffers = [];
|
|
48
|
+
ffmpeg.stdout.on("data", function (data) { return snapshotBuffers.push(data); });
|
|
49
|
+
ffmpeg.stderr.on("data", function (data) {
|
|
50
|
+
if (_this.ffmpegDebugOutput) {
|
|
52
51
|
console.log("SNAPSHOT: " + String(data));
|
|
53
52
|
}
|
|
54
53
|
});
|
|
55
|
-
ffmpeg.on("exit", (code, signal)
|
|
54
|
+
ffmpeg.on("exit", function (code, signal) {
|
|
56
55
|
if (signal) {
|
|
57
56
|
console.log("Snapshot process was killed with signal: " + signal);
|
|
58
57
|
callback(new Error("killed with signal " + signal));
|
|
59
58
|
}
|
|
60
59
|
else if (code === 0) {
|
|
61
|
-
console.log(
|
|
60
|
+
console.log("Successfully captured snapshot at ".concat(request.width, "x").concat(request.height));
|
|
62
61
|
callback(undefined, Buffer.concat(snapshotBuffers));
|
|
63
62
|
}
|
|
64
63
|
else {
|
|
@@ -66,18 +65,18 @@ class ExampleCamera {
|
|
|
66
65
|
callback(new Error("Snapshot process exited with code " + code));
|
|
67
66
|
}
|
|
68
67
|
});
|
|
69
|
-
}
|
|
68
|
+
};
|
|
70
69
|
// called when iOS request rtp setup
|
|
71
|
-
prepareStream(request, callback) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
ExampleCamera.prototype.prepareStream = function (request, callback) {
|
|
71
|
+
var sessionId = request.sessionID;
|
|
72
|
+
var targetAddress = request.targetAddress;
|
|
73
|
+
var video = request.video;
|
|
74
|
+
var videoCryptoSuite = video.srtpCryptoSuite; // could be used to support multiple crypto suite (or support no suite for debugging)
|
|
75
|
+
var videoSrtpKey = video.srtp_key;
|
|
76
|
+
var videoSrtpSalt = video.srtp_salt;
|
|
77
|
+
var videoSSRC = __1.CameraController.generateSynchronisationSource();
|
|
78
|
+
var localPort = getPort();
|
|
79
|
+
var sessionInfo = {
|
|
81
80
|
address: targetAddress,
|
|
82
81
|
videoPort: video.port,
|
|
83
82
|
localVideoPort: localPort,
|
|
@@ -85,7 +84,7 @@ class ExampleCamera {
|
|
|
85
84
|
videoSRTP: Buffer.concat([videoSrtpKey, videoSrtpSalt]),
|
|
86
85
|
videoSSRC: videoSSRC,
|
|
87
86
|
};
|
|
88
|
-
|
|
87
|
+
var response = {
|
|
89
88
|
video: {
|
|
90
89
|
port: localPort,
|
|
91
90
|
ssrc: videoSSRC,
|
|
@@ -96,37 +95,38 @@ class ExampleCamera {
|
|
|
96
95
|
};
|
|
97
96
|
this.pendingSessions[sessionId] = sessionInfo;
|
|
98
97
|
callback(undefined, response);
|
|
99
|
-
}
|
|
98
|
+
};
|
|
100
99
|
// called when iOS device asks stream to start/stop/reconfigure
|
|
101
|
-
handleStreamRequest(request, callback) {
|
|
102
|
-
|
|
100
|
+
ExampleCamera.prototype.handleStreamRequest = function (request, callback) {
|
|
101
|
+
var _this = this;
|
|
102
|
+
var sessionId = request.sessionID;
|
|
103
103
|
switch (request.type) {
|
|
104
104
|
case "start" /* StreamRequestTypes.START */: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
var sessionInfo = this.pendingSessions[sessionId];
|
|
106
|
+
var video = request.video;
|
|
107
|
+
var profile = FFMPEGH264ProfileNames[video.profile];
|
|
108
|
+
var level = FFMPEGH264LevelNames[video.level];
|
|
109
|
+
var width = video.width;
|
|
110
|
+
var height = video.height;
|
|
111
|
+
var fps = video.fps;
|
|
112
|
+
var payloadType = video.pt;
|
|
113
|
+
var maxBitrate = video.max_bit_rate;
|
|
114
114
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
console.log(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
var rtcpInterval = video.rtcp_interval; // usually 0.5
|
|
116
|
+
var mtu = video.mtu; // maximum transmission unit
|
|
117
|
+
var address = sessionInfo.address;
|
|
118
|
+
var videoPort = sessionInfo.videoPort;
|
|
119
|
+
var localVideoPort = sessionInfo.localVideoPort;
|
|
120
|
+
var ssrc = sessionInfo.videoSSRC;
|
|
121
|
+
var cryptoSuite = sessionInfo.videoCryptoSuite;
|
|
122
|
+
var videoSRTP = sessionInfo.videoSRTP.toString("base64");
|
|
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
128
|
if (cryptoSuite !== 2 /* SRTPCryptoSuites.NONE */) {
|
|
129
|
-
|
|
129
|
+
var suite = void 0;
|
|
130
130
|
switch (cryptoSuite) {
|
|
131
131
|
case 0 /* SRTPCryptoSuites.AES_CM_128_HMAC_SHA1_80 */: // actually ffmpeg just supports AES_CM_128_HMAC_SHA1_80
|
|
132
132
|
suite = "AES_CM_128_HMAC_SHA1_80";
|
|
@@ -135,41 +135,41 @@ class ExampleCamera {
|
|
|
135
135
|
suite = "AES_CM_256_HMAC_SHA1_80";
|
|
136
136
|
break;
|
|
137
137
|
}
|
|
138
|
-
videoffmpegCommand +=
|
|
138
|
+
videoffmpegCommand += "-srtp_out_suite ".concat(suite, " -srtp_out_params ").concat(videoSRTP, " s");
|
|
139
139
|
}
|
|
140
|
-
videoffmpegCommand +=
|
|
140
|
+
videoffmpegCommand += "rtp://".concat(address, ":").concat(videoPort, "?rtcpport=").concat(videoPort, "&localrtcpport=").concat(localVideoPort, "&pkt_size=").concat(mtu);
|
|
141
141
|
if (this.ffmpegDebugOutput) {
|
|
142
142
|
console.log("FFMPEG command: ffmpeg " + videoffmpegCommand);
|
|
143
143
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
ffmpegVideo.stderr.on("data", (data)
|
|
144
|
+
var ffmpegVideo = (0, child_process_1.spawn)("ffmpeg", videoffmpegCommand.split(" "), { env: process.env });
|
|
145
|
+
var started_1 = false;
|
|
146
|
+
ffmpegVideo.stderr.on("data", function (data) {
|
|
147
147
|
console.log(data.toString("utf8"));
|
|
148
|
-
if (!
|
|
149
|
-
|
|
148
|
+
if (!started_1) {
|
|
149
|
+
started_1 = true;
|
|
150
150
|
console.log("FFMPEG: received first frame");
|
|
151
151
|
callback(); // do not forget to execute callback once set up
|
|
152
152
|
}
|
|
153
|
-
if (
|
|
153
|
+
if (_this.ffmpegDebugOutput) {
|
|
154
154
|
console.log("VIDEO: " + String(data));
|
|
155
155
|
}
|
|
156
156
|
});
|
|
157
|
-
ffmpegVideo.on("error", error
|
|
157
|
+
ffmpegVideo.on("error", function (error) {
|
|
158
158
|
console.log("[Video] Failed to start video stream: " + error.message);
|
|
159
159
|
callback(new Error("ffmpeg process creation failed!"));
|
|
160
160
|
});
|
|
161
|
-
ffmpegVideo.on("exit", (code, signal)
|
|
162
|
-
|
|
161
|
+
ffmpegVideo.on("exit", function (code, signal) {
|
|
162
|
+
var message = "[Video] ffmpeg exited with code: " + code + " and signal: " + signal;
|
|
163
163
|
if (code == null || code === 255) {
|
|
164
164
|
console.log(message + " (Video stream stopped!)");
|
|
165
165
|
}
|
|
166
166
|
else {
|
|
167
167
|
console.log(message + " (error)");
|
|
168
|
-
if (!
|
|
168
|
+
if (!started_1) {
|
|
169
169
|
callback(new Error(message));
|
|
170
170
|
}
|
|
171
171
|
else {
|
|
172
|
-
|
|
172
|
+
_this.controller.forceStopStreamingSession(sessionId);
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
});
|
|
@@ -186,7 +186,7 @@ class ExampleCamera {
|
|
|
186
186
|
callback();
|
|
187
187
|
break;
|
|
188
188
|
case "stop" /* StreamRequestTypes.STOP */: {
|
|
189
|
-
|
|
189
|
+
var ongoingSession = this.ongoingSessions[sessionId];
|
|
190
190
|
if (!ongoingSession) {
|
|
191
191
|
callback();
|
|
192
192
|
break;
|
|
@@ -205,15 +205,15 @@ class ExampleCamera {
|
|
|
205
205
|
break;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
-
}
|
|
209
|
-
updateRecordingActive(active) {
|
|
208
|
+
};
|
|
209
|
+
ExampleCamera.prototype.updateRecordingActive = function (active) {
|
|
210
210
|
// we haven't implemented a prebuffer
|
|
211
211
|
console.log("Recording active set to " + active);
|
|
212
|
-
}
|
|
213
|
-
updateRecordingConfiguration(configuration) {
|
|
212
|
+
};
|
|
213
|
+
ExampleCamera.prototype.updateRecordingConfiguration = function (configuration) {
|
|
214
214
|
this.configuration = configuration;
|
|
215
215
|
console.log(configuration);
|
|
216
|
-
}
|
|
216
|
+
};
|
|
217
217
|
/**
|
|
218
218
|
* This is a very minimal, very experimental example on how to implement fmp4 streaming with a
|
|
219
219
|
* CameraController supporting HomeKit Secure Video.
|
|
@@ -224,234 +224,315 @@ class ExampleCamera {
|
|
|
224
224
|
* when the HomeKit Controller requests it (see the documentation of `CameraRecordingDelegate`).
|
|
225
225
|
*/
|
|
226
226
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
227
|
-
|
|
228
|
-
(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
break;
|
|
315
|
-
|
|
227
|
+
ExampleCamera.prototype.handleRecordingStreamRequest = function (streamId) {
|
|
228
|
+
return tslib_1.__asyncGenerator(this, arguments, function handleRecordingStreamRequest_1() {
|
|
229
|
+
var STOP_AFTER_MOTION_STOP, profile, level, videoArgs, samplerate, audioArgs, pending, _a, _b, _c, box, motionDetected, fragment, isLast, e_1_1, error_1;
|
|
230
|
+
var _d, e_1, _e, _f;
|
|
231
|
+
var _g, _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 = ((_h = (_g = this.controller) === null || _g === void 0 ? void 0 : _g.recordingManagement) === null || _h === void 0 ? void 0 : _h.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, 19, , 20]);
|
|
307
|
+
_k.label = 5;
|
|
308
|
+
case 5:
|
|
309
|
+
_k.trys.push([5, 12, 13, 18]);
|
|
310
|
+
_a = true, _b = tslib_1.__asyncValues(this.server.generator());
|
|
311
|
+
_k.label = 6;
|
|
312
|
+
case 6: return [4 /*yield*/, tslib_1.__await(_b.next())];
|
|
313
|
+
case 7:
|
|
314
|
+
if (!(_c = _k.sent(), _d = _c.done, !_d)) return [3 /*break*/, 11];
|
|
315
|
+
_f = _c.value;
|
|
316
|
+
_a = false;
|
|
317
|
+
box = _f;
|
|
318
|
+
pending.push(box.header, box.data);
|
|
319
|
+
motionDetected = (_j = camera.getService(__1.Service.MotionSensor)) === null || _j === void 0 ? void 0 : _j.getCharacteristic(__1.Characteristic.MotionDetected).value;
|
|
320
|
+
console.log("mp4 box type " + box.type + " and length " + box.length);
|
|
321
|
+
if (!(box.type === "moov" || box.type === "mdat")) return [3 /*break*/, 10];
|
|
322
|
+
fragment = Buffer.concat(pending);
|
|
323
|
+
pending.splice(0, pending.length);
|
|
324
|
+
isLast = STOP_AFTER_MOTION_STOP && !motionDetected;
|
|
325
|
+
return [4 /*yield*/, tslib_1.__await({
|
|
326
|
+
data: fragment,
|
|
327
|
+
isLast: isLast,
|
|
328
|
+
})];
|
|
329
|
+
case 8: return [4 /*yield*/, _k.sent()];
|
|
330
|
+
case 9:
|
|
331
|
+
_k.sent();
|
|
332
|
+
if (isLast) {
|
|
333
|
+
console.log("Ending session due to motion stopped!");
|
|
334
|
+
return [3 /*break*/, 11];
|
|
335
|
+
}
|
|
336
|
+
_k.label = 10;
|
|
337
|
+
case 10:
|
|
338
|
+
_a = true;
|
|
339
|
+
return [3 /*break*/, 6];
|
|
340
|
+
case 11: return [3 /*break*/, 18];
|
|
341
|
+
case 12:
|
|
342
|
+
e_1_1 = _k.sent();
|
|
343
|
+
e_1 = { error: e_1_1 };
|
|
344
|
+
return [3 /*break*/, 18];
|
|
345
|
+
case 13:
|
|
346
|
+
_k.trys.push([13, , 16, 17]);
|
|
347
|
+
if (!(!_a && !_d && (_e = _b.return))) return [3 /*break*/, 15];
|
|
348
|
+
return [4 /*yield*/, tslib_1.__await(_e.call(_b))];
|
|
349
|
+
case 14:
|
|
350
|
+
_k.sent();
|
|
351
|
+
_k.label = 15;
|
|
352
|
+
case 15: return [3 /*break*/, 17];
|
|
353
|
+
case 16:
|
|
354
|
+
if (e_1) throw e_1.error;
|
|
355
|
+
return [7 /*endfinally*/];
|
|
356
|
+
case 17: return [7 /*endfinally*/];
|
|
357
|
+
case 18: return [3 /*break*/, 20];
|
|
358
|
+
case 19:
|
|
359
|
+
error_1 = _k.sent();
|
|
360
|
+
if (!error_1.message.startsWith("FFMPEG")) { // cheap way of identifying our own emitted errors
|
|
361
|
+
console.error("Encountered unexpected error on generator " + error_1.stack);
|
|
362
|
+
}
|
|
363
|
+
return [3 /*break*/, 20];
|
|
364
|
+
case 20: return [2 /*return*/];
|
|
316
365
|
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (!error.message.startsWith("FFMPEG")) { // cheap way of identifying our own emitted errors
|
|
321
|
-
console.error("Encountered unexpected error on generator " + error.stack);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
};
|
|
325
369
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
326
|
-
closeRecordingStream(streamId, reason) {
|
|
370
|
+
ExampleCamera.prototype.closeRecordingStream = function (streamId, reason) {
|
|
327
371
|
if (this.server) {
|
|
328
372
|
this.server.destroy();
|
|
329
373
|
this.server = undefined;
|
|
330
374
|
}
|
|
331
375
|
this.handlingStreamingRequest = false;
|
|
332
|
-
}
|
|
333
|
-
acknowledgeStream(streamId) {
|
|
376
|
+
};
|
|
377
|
+
ExampleCamera.prototype.acknowledgeStream = function (streamId) {
|
|
334
378
|
this.closeRecordingStream(streamId);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
connectPromise;
|
|
349
|
-
connectResolve;
|
|
350
|
-
constructor(ffmpegPath, ffmpegInput, audioOutputArgs, videoOutputArgs) {
|
|
351
|
-
this.connectPromise = new Promise(resolve => this.connectResolve = resolve);
|
|
379
|
+
};
|
|
380
|
+
return ExampleCamera;
|
|
381
|
+
}());
|
|
382
|
+
var MP4StreamingServer = /** @class */ (function () {
|
|
383
|
+
function MP4StreamingServer(ffmpegPath, ffmpegInput, audioOutputArgs, videoOutputArgs) {
|
|
384
|
+
var _a, _b, _c;
|
|
385
|
+
var _this = this;
|
|
386
|
+
/**
|
|
387
|
+
* This can be configured to output ffmpeg debug output!
|
|
388
|
+
*/
|
|
389
|
+
this.debugMode = false;
|
|
390
|
+
this.destroyed = false;
|
|
391
|
+
this.connectPromise = new Promise(function (resolve) { return _this.connectResolve = resolve; });
|
|
352
392
|
this.server = (0, net_1.createServer)(this.handleConnection.bind(this));
|
|
353
393
|
this.ffmpegPath = ffmpegPath;
|
|
354
394
|
this.args = [];
|
|
355
|
-
this.args.push(
|
|
356
|
-
this.args.push(
|
|
395
|
+
(_a = this.args).push.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(ffmpegInput), false));
|
|
396
|
+
(_b = this.args).push.apply(_b, tslib_1.__spreadArray([], tslib_1.__read(audioOutputArgs), false));
|
|
357
397
|
this.args.push("-f", "mp4");
|
|
358
|
-
this.args.push(
|
|
398
|
+
(_c = this.args).push.apply(_c, tslib_1.__spreadArray([], tslib_1.__read(videoOutputArgs), false));
|
|
359
399
|
this.args.push("-fflags", "+genpts", "-reset_timestamps", "1");
|
|
360
400
|
this.args.push("-movflags", "frag_keyframe+empty_moov+default_base_moof");
|
|
361
401
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
402
|
+
MP4StreamingServer.prototype.start = function () {
|
|
403
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
404
|
+
var promise, port;
|
|
405
|
+
var _a, _b;
|
|
406
|
+
return tslib_1.__generator(this, function (_c) {
|
|
407
|
+
switch (_c.label) {
|
|
408
|
+
case 0:
|
|
409
|
+
promise = (0, events_1.once)(this.server, "listening");
|
|
410
|
+
this.server.listen(); // listen on random port
|
|
411
|
+
return [4 /*yield*/, promise];
|
|
412
|
+
case 1:
|
|
413
|
+
_c.sent();
|
|
414
|
+
if (this.destroyed) {
|
|
415
|
+
return [2 /*return*/];
|
|
416
|
+
}
|
|
417
|
+
port = this.server.address().port;
|
|
418
|
+
this.args.push("tcp://127.0.0.1:" + port);
|
|
419
|
+
console.log(this.ffmpegPath + " " + this.args.join(" "));
|
|
420
|
+
this.childProcess = (0, child_process_1.spawn)(this.ffmpegPath, this.args, { env: process.env, stdio: this.debugMode ? "pipe" : "ignore" });
|
|
421
|
+
if (!this.childProcess) {
|
|
422
|
+
console.error("ChildProcess is undefined directly after the init!");
|
|
423
|
+
}
|
|
424
|
+
if (this.debugMode) {
|
|
425
|
+
(_a = this.childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on("data", function (data) { return console.log(data.toString()); });
|
|
426
|
+
(_b = this.childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on("data", function (data) { return console.log(data.toString()); });
|
|
427
|
+
}
|
|
428
|
+
return [2 /*return*/];
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
};
|
|
433
|
+
MP4StreamingServer.prototype.destroy = function () {
|
|
434
|
+
var _a, _b;
|
|
435
|
+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
436
|
+
(_b = this.childProcess) === null || _b === void 0 ? void 0 : _b.kill();
|
|
384
437
|
this.socket = undefined;
|
|
385
438
|
this.childProcess = undefined;
|
|
386
439
|
this.destroyed = true;
|
|
387
|
-
}
|
|
388
|
-
handleConnection(socket) {
|
|
440
|
+
};
|
|
441
|
+
MP4StreamingServer.prototype.handleConnection = function (socket) {
|
|
442
|
+
var _a;
|
|
389
443
|
this.server.close(); // don't accept any further clients
|
|
390
444
|
this.socket = socket;
|
|
391
|
-
this.connectResolve
|
|
392
|
-
}
|
|
445
|
+
(_a = this.connectResolve) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
446
|
+
};
|
|
393
447
|
/**
|
|
394
448
|
* Generator for `MP4Atom`s.
|
|
395
449
|
* Throws error to signal EOF when socket is closed.
|
|
396
450
|
*/
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
451
|
+
MP4StreamingServer.prototype.generator = function () {
|
|
452
|
+
return tslib_1.__asyncGenerator(this, arguments, function generator_1() {
|
|
453
|
+
var header, length, type, data;
|
|
454
|
+
return tslib_1.__generator(this, function (_a) {
|
|
455
|
+
switch (_a.label) {
|
|
456
|
+
case 0: return [4 /*yield*/, tslib_1.__await(this.connectPromise)];
|
|
457
|
+
case 1:
|
|
458
|
+
_a.sent();
|
|
459
|
+
if (!this.socket || !this.childProcess) {
|
|
460
|
+
console.log("Socket undefined " + !!this.socket + " childProcess undefined " + !!this.childProcess);
|
|
461
|
+
throw new Error("Unexpected state!");
|
|
462
|
+
}
|
|
463
|
+
_a.label = 2;
|
|
464
|
+
case 2:
|
|
465
|
+
if (!true) return [3 /*break*/, 7];
|
|
466
|
+
return [4 /*yield*/, tslib_1.__await(this.read(8))];
|
|
467
|
+
case 3:
|
|
468
|
+
header = _a.sent();
|
|
469
|
+
length = header.readInt32BE(0) - 8;
|
|
470
|
+
type = header.slice(4).toString();
|
|
471
|
+
return [4 /*yield*/, tslib_1.__await(this.read(length))];
|
|
472
|
+
case 4:
|
|
473
|
+
data = _a.sent();
|
|
474
|
+
return [4 /*yield*/, tslib_1.__await({
|
|
475
|
+
header: header,
|
|
476
|
+
length: length,
|
|
477
|
+
type: type,
|
|
478
|
+
data: data,
|
|
479
|
+
})];
|
|
480
|
+
case 5: return [4 /*yield*/, _a.sent()];
|
|
481
|
+
case 6:
|
|
482
|
+
_a.sent();
|
|
483
|
+
return [3 /*break*/, 2];
|
|
484
|
+
case 7: return [2 /*return*/];
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
};
|
|
489
|
+
MP4StreamingServer.prototype.read = function (length) {
|
|
490
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
491
|
+
var value;
|
|
492
|
+
var _this = this;
|
|
493
|
+
return tslib_1.__generator(this, function (_a) {
|
|
494
|
+
if (!this.socket) {
|
|
495
|
+
throw Error("FFMPEG tried reading from closed socket!");
|
|
496
|
+
}
|
|
497
|
+
if (!length) {
|
|
498
|
+
return [2 /*return*/, Buffer.alloc(0)];
|
|
499
|
+
}
|
|
500
|
+
value = this.socket.read(length);
|
|
430
501
|
if (value) {
|
|
431
|
-
|
|
432
|
-
cleanup();
|
|
433
|
-
resolve(value);
|
|
502
|
+
return [2 /*return*/, value];
|
|
434
503
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
504
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
505
|
+
var readHandler = function () {
|
|
506
|
+
var value = _this.socket.read(length);
|
|
507
|
+
if (value) {
|
|
508
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
509
|
+
cleanup();
|
|
510
|
+
resolve(value);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
var endHandler = function () {
|
|
514
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
515
|
+
cleanup();
|
|
516
|
+
reject(new Error("FFMPEG socket closed during read for ".concat(length, " bytes!")));
|
|
517
|
+
};
|
|
518
|
+
var cleanup = function () {
|
|
519
|
+
var _a, _b;
|
|
520
|
+
(_a = _this.socket) === null || _a === void 0 ? void 0 : _a.removeListener("readable", readHandler);
|
|
521
|
+
(_b = _this.socket) === null || _b === void 0 ? void 0 : _b.removeListener("close", endHandler);
|
|
522
|
+
};
|
|
523
|
+
if (!_this.socket) {
|
|
524
|
+
throw new Error("FFMPEG socket is closed now!");
|
|
525
|
+
}
|
|
526
|
+
_this.socket.on("readable", readHandler);
|
|
527
|
+
_this.socket.on("close", endHandler);
|
|
528
|
+
})];
|
|
529
|
+
});
|
|
450
530
|
});
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
531
|
+
};
|
|
532
|
+
return MP4StreamingServer;
|
|
533
|
+
}());
|
|
534
|
+
var streamDelegate = new ExampleCamera();
|
|
535
|
+
var cameraController = new __1.CameraController({
|
|
455
536
|
cameraStreamCount: 2, // HomeKit requires at least 2 streams, but 1 is also just fine
|
|
456
537
|
delegate: streamDelegate,
|
|
457
538
|
streamingOptions: {
|
|
@@ -538,8 +619,8 @@ camera.configureController(cameraController);
|
|
|
538
619
|
// a service to trigger the motion sensor!
|
|
539
620
|
camera.addService(__1.Service.Switch, "MOTION TRIGGER")
|
|
540
621
|
.getCharacteristic(__1.Characteristic.On)
|
|
541
|
-
.onSet(value
|
|
542
|
-
|
|
543
|
-
|
|
622
|
+
.onSet(function (value) {
|
|
623
|
+
var _a;
|
|
624
|
+
(_a = camera.getService(__1.Service.MotionSensor)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(__1.Characteristic.MotionDetected, value);
|
|
544
625
|
});
|
|
545
626
|
//# sourceMappingURL=Camera_accessory.js.map
|