hap-nodejs 0.12.3-beta.2 → 0.12.3-beta.21
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 +1 -0
- 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 +292 -373
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +15 -21
- 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 +31 -21
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +45 -48
- 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 +36 -47
- 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.d.ts +0 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -28
- package/dist/index.js.map +1 -1
- package/dist/lib/Accessory.d.ts +1 -58
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +747 -1149
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/Advertiser.d.ts +1 -2
- package/dist/lib/Advertiser.d.ts.map +1 -1
- package/dist/lib/Advertiser.js +392 -524
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.js +6 -10
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.d.ts +2 -133
- package/dist/lib/Characteristic.d.ts.map +1 -1
- package/dist/lib/Characteristic.js +1467 -669
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.d.ts +0 -10
- package/dist/lib/HAPServer.d.ts.map +1 -1
- package/dist/lib/HAPServer.js +216 -280
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.d.ts +1 -51
- package/dist/lib/Service.d.ts.map +1 -1
- package/dist/lib/Service.js +474 -322
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/RTPProxy.js +112 -104
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.d.ts +0 -65
- package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +255 -278
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +318 -381
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.d.ts +0 -1
- package/dist/lib/camera/index.d.ts.map +1 -1
- package/dist/lib/camera/index.js +1 -2
- package/dist/lib/camera/index.js.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.d.ts +19 -3
- package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +217 -218
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.d.ts +0 -4
- package/dist/lib/controller/CameraController.d.ts.map +1 -1
- package/dist/lib/controller/CameraController.js +189 -256
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/DoorbellController.js +38 -39
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.d.ts +0 -14
- package/dist/lib/controller/RemoteController.d.ts.map +1 -1
- package/dist/lib/controller/RemoteController.js +340 -415
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.js +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +56 -57
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +259 -304
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts +0 -5
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +252 -269
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.js +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts +1 -106
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +2000 -2995
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.d.ts +0 -32
- package/dist/lib/definitions/ServiceDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +820 -1147
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +383 -679
- 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 +101 -136
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.js +86 -89
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.js +15 -16
- 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 +40 -44
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/checkName.d.ts +2 -1
- package/dist/lib/util/checkName.d.ts.map +1 -1
- package/dist/lib/util/checkName.js +7 -11
- package/dist/lib/util/checkName.js.map +1 -1
- package/dist/lib/util/clone.js +5 -27
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.js +8 -12
- 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 +301 -409
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.js +31 -32
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.js +9 -12
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.js +32 -53
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.js +3 -8
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.js +8 -13
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.js +2 -3
- 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.d.ts +0 -27
- package/dist/lib/util/tlv.d.ts.map +1 -1
- package/dist/lib/util/tlv.js +71 -113
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.d.ts +0 -9
- package/dist/lib/util/uuid.d.ts.map +1 -1
- package/dist/lib/util/uuid.js +15 -33
- package/dist/lib/util/uuid.js.map +1 -1
- package/dist/types.d.ts +0 -35
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -10
- package/dist/BridgedCore.d.ts +0 -2
- package/dist/BridgedCore.d.ts.map +0 -1
- package/dist/BridgedCore.js +0 -43
- package/dist/BridgedCore.js.map +0 -1
- package/dist/Core.d.ts +0 -2
- package/dist/Core.d.ts.map +0 -1
- package/dist/Core.js +0 -52
- package/dist/Core.js.map +0 -1
- package/dist/lib/AccessoryLoader.d.ts +0 -28
- package/dist/lib/AccessoryLoader.d.ts.map +0 -1
- package/dist/lib/AccessoryLoader.js +0 -166
- package/dist/lib/AccessoryLoader.js.map +0 -1
- package/dist/lib/camera/Camera.d.ts +0 -43
- package/dist/lib/camera/Camera.d.ts.map +0 -1
- package/dist/lib/camera/Camera.js +0 -36
- package/dist/lib/camera/Camera.js.map +0 -1
|
@@ -1,63 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const events_1 = require("events");
|
|
7
|
+
const net_1 = require("net");
|
|
8
|
+
const __1 = require("..");
|
|
9
|
+
const cameraUUID = __1.uuid.generate("hap-nodejs:accessories:ip-camera");
|
|
10
|
+
const 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
|
+
const FFMPEGH264ProfileNames = [
|
|
17
17
|
"baseline",
|
|
18
18
|
"main",
|
|
19
19
|
"high",
|
|
20
20
|
];
|
|
21
|
-
|
|
21
|
+
const FFMPEGH264LevelNames = [
|
|
22
22
|
"3.1",
|
|
23
23
|
"3.2",
|
|
24
24
|
"4.0",
|
|
25
25
|
];
|
|
26
|
-
|
|
26
|
+
const ports = new Set();
|
|
27
27
|
function getPort() {
|
|
28
|
-
for (
|
|
28
|
+
for (let 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
|
-
|
|
35
|
+
class ExampleCamera {
|
|
36
|
+
ffmpegDebugOutput = false;
|
|
37
|
+
controller;
|
|
38
|
+
// keep track of sessions
|
|
39
|
+
pendingSessions = {};
|
|
40
|
+
ongoingSessions = {};
|
|
41
|
+
// minimal secure video properties.
|
|
42
|
+
configuration;
|
|
43
|
+
handlingStreamingRequest = false;
|
|
44
|
+
server;
|
|
45
|
+
handleSnapshotRequest(request, callback) {
|
|
46
|
+
const ffmpegCommand = `-f lavfi -i testsrc=s=${request.width}x${request.height} -vframes 1 -f mjpeg -`;
|
|
47
|
+
const ffmpeg = (0, child_process_1.spawn)("ffmpeg", ffmpegCommand.split(" "), { env: process.env });
|
|
48
|
+
const snapshotBuffers = [];
|
|
49
|
+
ffmpeg.stdout.on("data", data => snapshotBuffers.push(data));
|
|
50
|
+
ffmpeg.stderr.on("data", data => {
|
|
51
|
+
if (this.ffmpegDebugOutput) {
|
|
51
52
|
console.log("SNAPSHOT: " + String(data));
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
|
-
ffmpeg.on("exit",
|
|
55
|
+
ffmpeg.on("exit", (code, signal) => {
|
|
55
56
|
if (signal) {
|
|
56
57
|
console.log("Snapshot process was killed with signal: " + signal);
|
|
57
58
|
callback(new Error("killed with signal " + signal));
|
|
58
59
|
}
|
|
59
60
|
else if (code === 0) {
|
|
60
|
-
console.log(
|
|
61
|
+
console.log(`Successfully captured snapshot at ${request.width}x${request.height}`);
|
|
61
62
|
callback(undefined, Buffer.concat(snapshotBuffers));
|
|
62
63
|
}
|
|
63
64
|
else {
|
|
@@ -65,18 +66,18 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
65
66
|
callback(new Error("Snapshot process exited with code " + code));
|
|
66
67
|
}
|
|
67
68
|
});
|
|
68
|
-
}
|
|
69
|
+
}
|
|
69
70
|
// called when iOS request rtp setup
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
prepareStream(request, callback) {
|
|
72
|
+
const sessionId = request.sessionID;
|
|
73
|
+
const targetAddress = request.targetAddress;
|
|
74
|
+
const video = request.video;
|
|
75
|
+
const videoCryptoSuite = video.srtpCryptoSuite; // could be used to support multiple crypto suite (or support no suite for debugging)
|
|
76
|
+
const videoSrtpKey = video.srtp_key;
|
|
77
|
+
const videoSrtpSalt = video.srtp_salt;
|
|
78
|
+
const videoSSRC = __1.CameraController.generateSynchronisationSource();
|
|
79
|
+
const localPort = getPort();
|
|
80
|
+
const sessionInfo = {
|
|
80
81
|
address: targetAddress,
|
|
81
82
|
videoPort: video.port,
|
|
82
83
|
localVideoPort: localPort,
|
|
@@ -84,7 +85,7 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
84
85
|
videoSRTP: Buffer.concat([videoSrtpKey, videoSrtpSalt]),
|
|
85
86
|
videoSSRC: videoSSRC,
|
|
86
87
|
};
|
|
87
|
-
|
|
88
|
+
const response = {
|
|
88
89
|
video: {
|
|
89
90
|
port: localPort,
|
|
90
91
|
ssrc: videoSSRC,
|
|
@@ -95,38 +96,37 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
95
96
|
};
|
|
96
97
|
this.pendingSessions[sessionId] = sessionInfo;
|
|
97
98
|
callback(undefined, response);
|
|
98
|
-
}
|
|
99
|
+
}
|
|
99
100
|
// called when iOS device asks stream to start/stop/reconfigure
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
var sessionId = request.sessionID;
|
|
101
|
+
handleStreamRequest(request, callback) {
|
|
102
|
+
const sessionId = request.sessionID;
|
|
103
103
|
switch (request.type) {
|
|
104
104
|
case "start" /* StreamRequestTypes.START */: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
const sessionInfo = this.pendingSessions[sessionId];
|
|
106
|
+
const video = request.video;
|
|
107
|
+
const profile = FFMPEGH264ProfileNames[video.profile];
|
|
108
|
+
const level = FFMPEGH264LevelNames[video.level];
|
|
109
|
+
const width = video.width;
|
|
110
|
+
const height = video.height;
|
|
111
|
+
const fps = video.fps;
|
|
112
|
+
const payloadType = video.pt;
|
|
113
|
+
const 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
|
+
const rtcpInterval = video.rtcp_interval; // usually 0.5
|
|
116
|
+
const mtu = video.mtu; // maximum transmission unit
|
|
117
|
+
const address = sessionInfo.address;
|
|
118
|
+
const videoPort = sessionInfo.videoPort;
|
|
119
|
+
const localVideoPort = sessionInfo.localVideoPort;
|
|
120
|
+
const ssrc = sessionInfo.videoSSRC;
|
|
121
|
+
const cryptoSuite = sessionInfo.videoCryptoSuite;
|
|
122
|
+
const videoSRTP = sessionInfo.videoSRTP.toString("base64");
|
|
123
|
+
console.log(`Starting video stream (${width}x${height}, ${fps} fps, ${maxBitrate} kbps, ${mtu} mtu)...`);
|
|
124
|
+
let videoffmpegCommand = `-re -f lavfi -i testsrc=s=${width}x${height}:r=${fps} -map 0:0 ` +
|
|
125
|
+
`-c:v h264 -pix_fmt yuv420p -r ${fps} -an -sn -dn -b:v ${maxBitrate}k ` +
|
|
126
|
+
`-profile:v ${profile} -level:v ${level} ` +
|
|
127
|
+
`-payload_type ${payloadType} -ssrc ${ssrc} -f rtp `;
|
|
128
128
|
if (cryptoSuite !== 2 /* SRTPCryptoSuites.NONE */) {
|
|
129
|
-
|
|
129
|
+
let suite;
|
|
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 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
135
135
|
suite = "AES_CM_256_HMAC_SHA1_80";
|
|
136
136
|
break;
|
|
137
137
|
}
|
|
138
|
-
videoffmpegCommand +=
|
|
138
|
+
videoffmpegCommand += `-srtp_out_suite ${suite} -srtp_out_params ${videoSRTP} s`;
|
|
139
139
|
}
|
|
140
|
-
videoffmpegCommand +=
|
|
140
|
+
videoffmpegCommand += `rtp://${address}:${videoPort}?rtcpport=${videoPort}&localrtcpport=${localVideoPort}&pkt_size=${mtu}`;
|
|
141
141
|
if (this.ffmpegDebugOutput) {
|
|
142
142
|
console.log("FFMPEG command: ffmpeg " + videoffmpegCommand);
|
|
143
143
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
ffmpegVideo.stderr.on("data",
|
|
144
|
+
const ffmpegVideo = (0, child_process_1.spawn)("ffmpeg", videoffmpegCommand.split(" "), { env: process.env });
|
|
145
|
+
let started = false;
|
|
146
|
+
ffmpegVideo.stderr.on("data", (data) => {
|
|
147
147
|
console.log(data.toString("utf8"));
|
|
148
|
-
if (!
|
|
149
|
-
|
|
148
|
+
if (!started) {
|
|
149
|
+
started = 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",
|
|
157
|
+
ffmpegVideo.on("error", 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",
|
|
162
|
-
|
|
161
|
+
ffmpegVideo.on("exit", (code, signal) => {
|
|
162
|
+
const 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) {
|
|
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 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
186
186
|
callback();
|
|
187
187
|
break;
|
|
188
188
|
case "stop" /* StreamRequestTypes.STOP */: {
|
|
189
|
-
|
|
189
|
+
const ongoingSession = this.ongoingSessions[sessionId];
|
|
190
190
|
if (!ongoingSession) {
|
|
191
191
|
callback();
|
|
192
192
|
break;
|
|
@@ -205,15 +205,15 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
205
205
|
break;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
-
}
|
|
209
|
-
|
|
208
|
+
}
|
|
209
|
+
updateRecordingActive(active) {
|
|
210
210
|
// we haven't implemented a prebuffer
|
|
211
211
|
console.log("Recording active set to " + active);
|
|
212
|
-
}
|
|
213
|
-
|
|
212
|
+
}
|
|
213
|
+
updateRecordingConfiguration(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,315 +224,234 @@ var ExampleCamera = /** @class */ (function () {
|
|
|
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
|
-
|
|
315
|
-
|
|
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*/];
|
|
227
|
+
async *handleRecordingStreamRequest(streamId) {
|
|
228
|
+
(0, assert_1.default)(!!this.configuration);
|
|
229
|
+
/**
|
|
230
|
+
* With this flag you can control how the generator reacts to a reset to the motion trigger.
|
|
231
|
+
* If set to true, the generator will send a proper endOfStream if the motion stops.
|
|
232
|
+
* If set to false, the generator will run till the HomeKit Controller closes the stream.
|
|
233
|
+
*
|
|
234
|
+
* Note: In a real implementation you would most likely introduce a bit of a delay.
|
|
235
|
+
*/
|
|
236
|
+
const STOP_AFTER_MOTION_STOP = false;
|
|
237
|
+
this.handlingStreamingRequest = true;
|
|
238
|
+
(0, assert_1.default)(this.configuration.videoCodec.type === 0 /* VideoCodecType.H264 */);
|
|
239
|
+
const profile = this.configuration.videoCodec.parameters.profile === 2 /* H264Profile.HIGH */ ? "high"
|
|
240
|
+
: this.configuration.videoCodec.parameters.profile === 1 /* H264Profile.MAIN */ ? "main" : "baseline";
|
|
241
|
+
const 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
|
+
const 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", `${this.configuration.videoCodec.parameters.bitRate}k`,
|
|
254
|
+
"-force_key_frames", `expr:eq(t,n_forced*${this.configuration.videoCodec.parameters.iFrameInterval / 1000})`,
|
|
255
|
+
"-r", this.configuration.videoCodec.resolution[2].toString(),
|
|
256
|
+
];
|
|
257
|
+
let samplerate;
|
|
258
|
+
switch (this.configuration.audioCodec.samplerate) {
|
|
259
|
+
case 0 /* AudioRecordingSamplerate.KHZ_8 */:
|
|
260
|
+
samplerate = "8";
|
|
261
|
+
break;
|
|
262
|
+
case 1 /* AudioRecordingSamplerate.KHZ_16 */:
|
|
263
|
+
samplerate = "16";
|
|
264
|
+
break;
|
|
265
|
+
case 2 /* AudioRecordingSamplerate.KHZ_24 */:
|
|
266
|
+
samplerate = "24";
|
|
267
|
+
break;
|
|
268
|
+
case 3 /* AudioRecordingSamplerate.KHZ_32 */:
|
|
269
|
+
samplerate = "32";
|
|
270
|
+
break;
|
|
271
|
+
case 4 /* AudioRecordingSamplerate.KHZ_44_1 */:
|
|
272
|
+
samplerate = "44.1";
|
|
273
|
+
break;
|
|
274
|
+
case 5 /* AudioRecordingSamplerate.KHZ_48 */:
|
|
275
|
+
samplerate = "48";
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
throw new Error("Unsupported audio samplerate: " + this.configuration.audioCodec.samplerate);
|
|
279
|
+
}
|
|
280
|
+
const audioArgs = this.controller?.recordingManagement?.recordingManagementService.getCharacteristic(__1.Characteristic.RecordingAudioActive)
|
|
281
|
+
? [
|
|
282
|
+
"-acodec", "libfdk_aac",
|
|
283
|
+
...(this.configuration.audioCodec.type === 0 /* AudioRecordingCodecType.AAC_LC */ ?
|
|
284
|
+
["-profile:a", "aac_low"] :
|
|
285
|
+
["-profile:a", "aac_eld"]),
|
|
286
|
+
"-ar", `${samplerate}k`,
|
|
287
|
+
"-b:a", `${this.configuration.audioCodec.bitrate}k`,
|
|
288
|
+
"-ac", `${this.configuration.audioCodec.audioChannels}`,
|
|
289
|
+
]
|
|
290
|
+
: [];
|
|
291
|
+
this.server = new MP4StreamingServer("ffmpeg", `-f lavfi -i \
|
|
292
|
+
testsrc=s=${this.configuration.videoCodec.resolution[0]}x${this.configuration.videoCodec.resolution[1]}:r=${this.configuration.videoCodec.resolution[2]}`
|
|
293
|
+
.split(/ /g), audioArgs, videoArgs);
|
|
294
|
+
await this.server.start();
|
|
295
|
+
if (!this.server || this.server.destroyed) {
|
|
296
|
+
return; // early exit
|
|
297
|
+
}
|
|
298
|
+
const pending = [];
|
|
299
|
+
try {
|
|
300
|
+
for await (const box of this.server.generator()) {
|
|
301
|
+
pending.push(box.header, box.data);
|
|
302
|
+
const motionDetected = camera.getService(__1.Service.MotionSensor)?.getCharacteristic(__1.Characteristic.MotionDetected).value;
|
|
303
|
+
console.log("mp4 box type " + box.type + " and length " + box.length);
|
|
304
|
+
if (box.type === "moov" || box.type === "mdat") {
|
|
305
|
+
const fragment = Buffer.concat(pending);
|
|
306
|
+
pending.splice(0, pending.length);
|
|
307
|
+
const isLast = STOP_AFTER_MOTION_STOP && !motionDetected;
|
|
308
|
+
yield {
|
|
309
|
+
data: fragment,
|
|
310
|
+
isLast: isLast,
|
|
311
|
+
};
|
|
312
|
+
if (isLast) {
|
|
313
|
+
console.log("Ending session due to motion stopped!");
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
365
316
|
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
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
|
+
}
|
|
369
325
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
370
|
-
|
|
326
|
+
closeRecordingStream(streamId, reason) {
|
|
371
327
|
if (this.server) {
|
|
372
328
|
this.server.destroy();
|
|
373
329
|
this.server = undefined;
|
|
374
330
|
}
|
|
375
331
|
this.handlingStreamingRequest = false;
|
|
376
|
-
}
|
|
377
|
-
|
|
332
|
+
}
|
|
333
|
+
acknowledgeStream(streamId) {
|
|
378
334
|
this.closeRecordingStream(streamId);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
class MP4StreamingServer {
|
|
338
|
+
server;
|
|
339
|
+
/**
|
|
340
|
+
* This can be configured to output ffmpeg debug output!
|
|
341
|
+
*/
|
|
342
|
+
debugMode = false;
|
|
343
|
+
ffmpegPath;
|
|
344
|
+
args;
|
|
345
|
+
socket;
|
|
346
|
+
childProcess;
|
|
347
|
+
destroyed = false;
|
|
348
|
+
connectPromise;
|
|
349
|
+
connectResolve;
|
|
350
|
+
constructor(ffmpegPath, ffmpegInput, audioOutputArgs, videoOutputArgs) {
|
|
351
|
+
this.connectPromise = new Promise(resolve => this.connectResolve = resolve);
|
|
392
352
|
this.server = (0, net_1.createServer)(this.handleConnection.bind(this));
|
|
393
353
|
this.ffmpegPath = ffmpegPath;
|
|
394
354
|
this.args = [];
|
|
395
|
-
|
|
396
|
-
|
|
355
|
+
this.args.push(...ffmpegInput);
|
|
356
|
+
this.args.push(...audioOutputArgs);
|
|
397
357
|
this.args.push("-f", "mp4");
|
|
398
|
-
|
|
358
|
+
this.args.push(...videoOutputArgs);
|
|
399
359
|
this.args.push("-fflags", "+genpts", "-reset_timestamps", "1");
|
|
400
360
|
this.args.push("-movflags", "frag_keyframe+empty_moov+default_base_moof");
|
|
401
361
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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();
|
|
362
|
+
async start() {
|
|
363
|
+
const promise = (0, events_1.once)(this.server, "listening");
|
|
364
|
+
this.server.listen(); // listen on random port
|
|
365
|
+
await promise;
|
|
366
|
+
if (this.destroyed) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
const port = this.server.address().port;
|
|
370
|
+
this.args.push("tcp://127.0.0.1:" + port);
|
|
371
|
+
console.log(this.ffmpegPath + " " + this.args.join(" "));
|
|
372
|
+
this.childProcess = (0, child_process_1.spawn)(this.ffmpegPath, this.args, { env: process.env, stdio: this.debugMode ? "pipe" : "ignore" });
|
|
373
|
+
if (!this.childProcess) {
|
|
374
|
+
console.error("ChildProcess is undefined directly after the init!");
|
|
375
|
+
}
|
|
376
|
+
if (this.debugMode) {
|
|
377
|
+
this.childProcess.stdout?.on("data", data => console.log(data.toString()));
|
|
378
|
+
this.childProcess.stderr?.on("data", data => console.log(data.toString()));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
destroy() {
|
|
382
|
+
this.socket?.destroy();
|
|
383
|
+
this.childProcess?.kill();
|
|
437
384
|
this.socket = undefined;
|
|
438
385
|
this.childProcess = undefined;
|
|
439
386
|
this.destroyed = true;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
var _a;
|
|
387
|
+
}
|
|
388
|
+
handleConnection(socket) {
|
|
443
389
|
this.server.close(); // don't accept any further clients
|
|
444
390
|
this.socket = socket;
|
|
445
|
-
|
|
446
|
-
}
|
|
391
|
+
this.connectResolve?.();
|
|
392
|
+
}
|
|
447
393
|
/**
|
|
448
394
|
* Generator for `MP4Atom`s.
|
|
449
395
|
* Throws error to signal EOF when socket is closed.
|
|
450
396
|
*/
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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);
|
|
397
|
+
async *generator() {
|
|
398
|
+
await this.connectPromise;
|
|
399
|
+
if (!this.socket || !this.childProcess) {
|
|
400
|
+
console.log("Socket undefined " + !!this.socket + " childProcess undefined " + !!this.childProcess);
|
|
401
|
+
throw new Error("Unexpected state!");
|
|
402
|
+
}
|
|
403
|
+
while (true) {
|
|
404
|
+
const header = await this.read(8);
|
|
405
|
+
const length = header.readInt32BE(0) - 8;
|
|
406
|
+
const type = header.slice(4).toString();
|
|
407
|
+
const data = await this.read(length);
|
|
408
|
+
yield {
|
|
409
|
+
header: header,
|
|
410
|
+
length: length,
|
|
411
|
+
type: type,
|
|
412
|
+
data: data,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
async read(length) {
|
|
417
|
+
if (!this.socket) {
|
|
418
|
+
throw Error("FFMPEG tried reading from closed socket!");
|
|
419
|
+
}
|
|
420
|
+
if (!length) {
|
|
421
|
+
return Buffer.alloc(0);
|
|
422
|
+
}
|
|
423
|
+
const value = this.socket.read(length);
|
|
424
|
+
if (value) {
|
|
425
|
+
return value;
|
|
426
|
+
}
|
|
427
|
+
return new Promise((resolve, reject) => {
|
|
428
|
+
const readHandler = () => {
|
|
429
|
+
const value = this.socket.read(length);
|
|
501
430
|
if (value) {
|
|
502
|
-
|
|
431
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
432
|
+
cleanup();
|
|
433
|
+
resolve(value);
|
|
503
434
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
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
|
-
});
|
|
435
|
+
};
|
|
436
|
+
const endHandler = () => {
|
|
437
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
438
|
+
cleanup();
|
|
439
|
+
reject(new Error(`FFMPEG socket closed during read for ${length} bytes!`));
|
|
440
|
+
};
|
|
441
|
+
const cleanup = () => {
|
|
442
|
+
this.socket?.removeListener("readable", readHandler);
|
|
443
|
+
this.socket?.removeListener("close", endHandler);
|
|
444
|
+
};
|
|
445
|
+
if (!this.socket) {
|
|
446
|
+
throw new Error("FFMPEG socket is closed now!");
|
|
447
|
+
}
|
|
448
|
+
this.socket.on("readable", readHandler);
|
|
449
|
+
this.socket.on("close", endHandler);
|
|
530
450
|
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
var cameraController = new __1.CameraController({
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const streamDelegate = new ExampleCamera();
|
|
454
|
+
const cameraController = new __1.CameraController({
|
|
536
455
|
cameraStreamCount: 2, // HomeKit requires at least 2 streams, but 1 is also just fine
|
|
537
456
|
delegate: streamDelegate,
|
|
538
457
|
streamingOptions: {
|
|
@@ -619,8 +538,8 @@ camera.configureController(cameraController);
|
|
|
619
538
|
// a service to trigger the motion sensor!
|
|
620
539
|
camera.addService(__1.Service.Switch, "MOTION TRIGGER")
|
|
621
540
|
.getCharacteristic(__1.Characteristic.On)
|
|
622
|
-
.onSet(
|
|
623
|
-
|
|
624
|
-
|
|
541
|
+
.onSet(value => {
|
|
542
|
+
camera.getService(__1.Service.MotionSensor)
|
|
543
|
+
?.updateCharacteristic(__1.Characteristic.MotionDetected, value);
|
|
625
544
|
});
|
|
626
545
|
//# sourceMappingURL=Camera_accessory.js.map
|