@camera.ui/camera-ui-homekit 0.0.2

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 (49) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/CONTRIBUTING.md +1 -0
  3. package/LICENSE.md +22 -0
  4. package/README.md +1 -0
  5. package/config.schema.json +15 -0
  6. package/dist/camera/accessory.d.ts +27 -0
  7. package/dist/camera/accessory.js +327 -0
  8. package/dist/camera/accessory.js.map +1 -0
  9. package/dist/camera/recordingDelegate.d.ts +27 -0
  10. package/dist/camera/recordingDelegate.js +263 -0
  11. package/dist/camera/recordingDelegate.js.map +1 -0
  12. package/dist/camera/services.d.ts +22 -0
  13. package/dist/camera/services.js +171 -0
  14. package/dist/camera/services.js.map +1 -0
  15. package/dist/camera/sessionWrapper.d.ts +25 -0
  16. package/dist/camera/sessionWrapper.js +287 -0
  17. package/dist/camera/sessionWrapper.js.map +1 -0
  18. package/dist/camera/streamingDelegate.d.ts +13 -0
  19. package/dist/camera/streamingDelegate.js +96 -0
  20. package/dist/camera/streamingDelegate.js.map +1 -0
  21. package/dist/camera/streamingServer.d.ts +24 -0
  22. package/dist/camera/streamingServer.js +143 -0
  23. package/dist/camera/streamingServer.js.map +1 -0
  24. package/dist/crypto.d.ts +1 -0
  25. package/dist/crypto.js +29 -0
  26. package/dist/crypto.js.map +1 -0
  27. package/dist/index.d.ts +19 -0
  28. package/dist/index.js +57 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/types.d.ts +10 -0
  31. package/dist/types.js +2 -0
  32. package/dist/types.js.map +1 -0
  33. package/dist/utils/codecs.d.ts +1 -0
  34. package/dist/utils/codecs.js +2 -0
  35. package/dist/utils/codecs.js.map +1 -0
  36. package/dist/utils/ffmpeg.d.ts +11 -0
  37. package/dist/utils/ffmpeg.js +66 -0
  38. package/dist/utils/ffmpeg.js.map +1 -0
  39. package/dist/utils/mac.d.ts +4 -0
  40. package/dist/utils/mac.js +19 -0
  41. package/dist/utils/mac.js.map +1 -0
  42. package/dist/utils/opus-repacketizer.d.ts +7 -0
  43. package/dist/utils/opus-repacketizer.js +163 -0
  44. package/dist/utils/opus-repacketizer.js.map +1 -0
  45. package/media/cameraOffline.png +0 -0
  46. package/media/maxStreams.png +0 -0
  47. package/media/noSnapshot.png +0 -0
  48. package/media/privacyMode.png +0 -0
  49. package/package.json +62 -0
@@ -0,0 +1,287 @@
1
+ import { ReturnAudioTranscoder, RtpSplitter, doesFfmpegSupportCodec, generateSrtpOptions } from '@homebridge/camera-utils';
2
+ import { CameraController } from 'hap-nodejs';
3
+ import { Subject, interval, merge, of } from 'rxjs';
4
+ import { debounceTime, delay, take } from 'rxjs/operators';
5
+ import { RtcpSenderInfo, RtcpSrPacket, RtpPacket, SrtcpSession, SrtpSession } from 'werift';
6
+ import { OpusRepacketizer } from '../utils/opus-repacketizer.js';
7
+ function getSessionConfig(srtpOptions) {
8
+ return {
9
+ keys: {
10
+ localMasterKey: srtpOptions.srtpKey,
11
+ localMasterSalt: srtpOptions.srtpSalt,
12
+ remoteMasterKey: srtpOptions.srtpKey,
13
+ remoteMasterSalt: srtpOptions.srtpSalt,
14
+ },
15
+ profile: 1,
16
+ };
17
+ }
18
+ function getDurationSeconds(start) {
19
+ return (Date.now() - start) / 1000;
20
+ }
21
+ export class StreamingSessionWrapper {
22
+ start;
23
+ audioSsrc = CameraController.generateSynchronisationSource();
24
+ videoSsrc = CameraController.generateSynchronisationSource();
25
+ audioSrtp = generateSrtpOptions();
26
+ videoSrtp = generateSrtpOptions();
27
+ audioSplitter = new RtpSplitter();
28
+ videoSplitter = new RtpSplitter();
29
+ cameraAccessory;
30
+ cameraDevice;
31
+ streamingSession;
32
+ prepareStreamRequest;
33
+ logger;
34
+ repacketizeAudioSplitter = new RtpSplitter();
35
+ constructor(cameraAccessory, cameraDevice, streamingSession, prepareStreamRequest, start, logger) {
36
+ this.cameraAccessory = cameraAccessory;
37
+ this.cameraDevice = cameraDevice;
38
+ this.streamingSession = streamingSession;
39
+ this.prepareStreamRequest = prepareStreamRequest;
40
+ this.start = start;
41
+ this.logger = logger;
42
+ const { targetAddress, video: { port: videoPort }, } = prepareStreamRequest;
43
+ // used to encrypt rtcp to HomeKit for keepalive
44
+ const videoSrtcpSession = new SrtcpSession(getSessionConfig(this.videoSrtp));
45
+ const onReturnPacketReceived = new Subject();
46
+ // Watch return packets to detect a dead stream from the HomeKit side
47
+ // This can happen if the user force-quits the Home app
48
+ this.videoSplitter.addMessageHandler(() => {
49
+ // return packet from HomeKit
50
+ onReturnPacketReceived.next(null);
51
+ return null;
52
+ });
53
+ this.audioSplitter.addMessageHandler(() => {
54
+ // return packet from HomeKit
55
+ onReturnPacketReceived.next(null);
56
+ return null;
57
+ });
58
+ streamingSession.addSubscriptions(merge(of(true).pipe(delay(15000)), onReturnPacketReceived)
59
+ .pipe(debounceTime(5000))
60
+ .subscribe(() => {
61
+ this.logger.log(this.cameraDevice.name, `Live stream appears to be inactive. (${getDurationSeconds(start)}s)`);
62
+ streamingSession.stop();
63
+ }));
64
+ // Periodically send a blank RTCP packet to the HomeKit video port
65
+ // Without this, HomeKit assumes the stream is dead after 30 second and sends a stop request
66
+ streamingSession.addSubscriptions(interval(500).subscribe(() => {
67
+ const senderInfo = new RtcpSenderInfo({
68
+ ntpTimestamp: BigInt(0),
69
+ packetCount: 0,
70
+ octetCount: 0,
71
+ rtpTimestamp: 0,
72
+ });
73
+ const senderReport = new RtcpSrPacket({
74
+ ssrc: this.videoSsrc,
75
+ senderInfo: senderInfo,
76
+ });
77
+ const message = videoSrtcpSession.encrypt(senderReport.serialize());
78
+ this.videoSplitter
79
+ .send(message, {
80
+ port: videoPort,
81
+ address: targetAddress,
82
+ })
83
+ .catch((error) => {
84
+ this.logger.error(this.cameraDevice.name, 'Failed to send RTCP packet', error);
85
+ });
86
+ }));
87
+ }
88
+ async activate(request) {
89
+ let sentVideo = false;
90
+ const { targetAddress, video: { port: videoPort }, } = this.prepareStreamRequest;
91
+ // use to encrypt video to HomeKit
92
+ const videoSrtpSession = new SrtpSession(getSessionConfig(this.videoSrtp));
93
+ // Set up packet forwarding for video stream
94
+ this.streamingSession.addSubscriptions(this.streamingSession.onVideoRtp.subscribe(({ header, payload }) => {
95
+ header.ssrc = this.videoSsrc;
96
+ header.payloadType = request.video.pt;
97
+ const encryptedPacket = videoSrtpSession.encrypt(payload, header);
98
+ if (!sentVideo) {
99
+ sentVideo = true;
100
+ this.logger.debug(this.cameraDevice.name, `Received stream data (${getDurationSeconds(this.start)}s)`);
101
+ }
102
+ this.videoSplitter
103
+ .send(encryptedPacket, {
104
+ port: videoPort,
105
+ address: targetAddress,
106
+ })
107
+ .catch((error) => {
108
+ this.logger.error(this.cameraDevice.name, 'Failed to forward video packet', error);
109
+ });
110
+ }));
111
+ const shouldTranscodeAudio = await this.libfdkAacInstalledPromise();
112
+ if (!shouldTranscodeAudio) {
113
+ return this.streamingSession.requestKeyFrame();
114
+ }
115
+ const transcodingPromise = this.streamingSession.startTranscoding({
116
+ input: ['-vn'],
117
+ audio: [
118
+ '-map',
119
+ '0:a',
120
+ ...(request.audio.codec === "OPUS" /* AudioStreamingCodecType.OPUS */
121
+ ? [
122
+ // OPUS specific - it works, but audio is very choppy
123
+ '-acodec',
124
+ 'libopus',
125
+ '-frame_duration',
126
+ request.audio.packet_time,
127
+ '-application',
128
+ 'lowdelay',
129
+ ]
130
+ : [
131
+ // AAC-eld specific
132
+ '-acodec',
133
+ 'libfdk_aac',
134
+ '-profile:a',
135
+ 'aac_eld',
136
+ '-eld_sbr:a',
137
+ '1',
138
+ '-eld_v2',
139
+ '1',
140
+ ]),
141
+ // Shared options
142
+ '-flags',
143
+ '+global_header',
144
+ '-ac',
145
+ `${request.audio.channel}`,
146
+ '-ar',
147
+ `${request.audio.sample_rate}k`,
148
+ '-b:a',
149
+ `${request.audio.max_bit_rate}k`,
150
+ '-bufsize',
151
+ `${request.audio.max_bit_rate * 4}k`,
152
+ '-payload_type',
153
+ request.audio.pt,
154
+ '-ssrc',
155
+ this.audioSsrc,
156
+ '-f',
157
+ 'rtp',
158
+ `rtp://127.0.0.1:${await this.repacketizeAudioSplitter.portPromise}?pkt_size=376`,
159
+ ],
160
+ video: false,
161
+ output: [],
162
+ });
163
+ const twoWayAudio = await this.cameraAccessory.cameraStorage.getValue('twoWayAudio', true);
164
+ let returnAudioTranscodedSplitter;
165
+ let returnAudioTranscoder;
166
+ const returnAudioCodecs = [];
167
+ if (twoWayAudio) {
168
+ // used to send return audio from HomeKit to Camera
169
+ returnAudioTranscodedSplitter = new RtpSplitter(({ message }) => {
170
+ // deserialize and send to Camera - werift will handle encryption and other header params
171
+ try {
172
+ const rtp = RtpPacket.deSerialize(message);
173
+ this.streamingSession.sendAudioPacket(rtp);
174
+ }
175
+ catch {
176
+ // deSerialize will sometimes fail, but the errors can be ignored
177
+ }
178
+ return null;
179
+ });
180
+ const returnAudioCodec = await this.cameraAccessory.cameraStorage.getValue('returnAudioCodec');
181
+ const isCameraUsingOpus = (await this.streamingSession.isUsingOpus) || (returnAudioCodec && returnAudioCodec === 'libopus');
182
+ if (returnAudioCodec === 'libopus' || (!returnAudioCodec && isCameraUsingOpus)) {
183
+ returnAudioCodecs.push('-acodec', 'libopus', '-ac', '2', '-ar', '24k', '-b:a', '24k', '-application', 'lowdelay');
184
+ }
185
+ if (returnAudioCodec === 'pcm_mulaw' || (!returnAudioCodec && !isCameraUsingOpus)) {
186
+ returnAudioCodecs.push('-acodec', 'pcm_mulaw', '-ac', '1', '-ar', '8k');
187
+ }
188
+ if (returnAudioCodec === 'pcm_alaw') {
189
+ returnAudioCodecs.push('-acodec', 'pcm_alaw', '-ac', '1', '-ar', '8k');
190
+ }
191
+ returnAudioTranscoder = new ReturnAudioTranscoder({
192
+ prepareStreamRequest: this.prepareStreamRequest,
193
+ startStreamRequest: request,
194
+ incomingAudioOptions: {
195
+ ssrc: this.audioSsrc,
196
+ rtcpPort: 0, // we don't care about rtcp for incoming audio
197
+ },
198
+ outputArgs: [...returnAudioCodecs, '-flags', '+global_header', '-f', 'rtp', `rtp://127.0.0.1:${await returnAudioTranscodedSplitter.portPromise}`],
199
+ ffmpegPath: await this.cameraDevice.getFfmpegPath(),
200
+ returnAudioSplitter: this.audioSplitter,
201
+ logger: {
202
+ info: () => { },
203
+ // info: (message: string) => this.logger.debug(this.cameraDevice.name, message),
204
+ error: (message) => this.logger.error(this.cameraDevice.name, 'Return Audio:', message),
205
+ },
206
+ });
207
+ this.streamingSession.onCallEnded.pipe(take(1)).subscribe(() => {
208
+ returnAudioTranscoder?.stop();
209
+ returnAudioTranscodedSplitter?.close();
210
+ });
211
+ }
212
+ this.listenForAudioPackets(request);
213
+ await returnAudioTranscoder?.start();
214
+ await transcodingPromise;
215
+ }
216
+ stop() {
217
+ this.audioSplitter.close();
218
+ this.repacketizeAudioSplitter.close();
219
+ this.videoSplitter.close();
220
+ this.streamingSession.stop();
221
+ }
222
+ listenForAudioPackets(startStreamRequest) {
223
+ const { targetAddress, audio: { port: audioPort }, } = this.prepareStreamRequest;
224
+ const { audio: { codec: audioCodec, sample_rate: audioSampleRate, packet_time: audioPacketTime }, } = startStreamRequest;
225
+ // Repacketize the audio stream after it's been transcoded
226
+ const opusRepacketizer = new OpusRepacketizer(audioPacketTime / 20);
227
+ const audioIntervalScale = ((audioSampleRate / 8) * audioPacketTime) / 20;
228
+ const audioSrtpSession = new SrtpSession(getSessionConfig(this.audioSrtp));
229
+ let firstTimestamp, audioPacketCount = 0;
230
+ this.repacketizeAudioSplitter.addMessageHandler(({ message }) => {
231
+ let rtp = RtpPacket.deSerialize(message);
232
+ if (audioCodec === "OPUS" /* AudioStreamingCodecType.OPUS */) {
233
+ // borrowed from scrypted
234
+ // Original source: https://github.com/koush/scrypted/blob/c13ba09889c3e0d9d3724cb7d49253c9d787fb97/plugins/homekit/src/types/camera/camera-streaming-srtp-sender.ts#L124-L143
235
+ rtp = opusRepacketizer.repacketize(rtp);
236
+ if (!rtp) {
237
+ return null;
238
+ }
239
+ if (!firstTimestamp) {
240
+ firstTimestamp = rtp.header.timestamp;
241
+ }
242
+ // from HAP spec:
243
+ // RTP Payload Format for Opus Speech and Audio Codec RFC 7587 with an exception
244
+ // that Opus audio RTP Timestamp shall be based on RFC 3550.
245
+ // RFC 3550 indicates that PCM audio based with a sample rate of 8k and a packet
246
+ // time of 20ms would have a monotonic interval of 8k / (1000 / 20) = 160.
247
+ // So 24k audio would have a monotonic interval of (24k / 8k) * 160 = 480.
248
+ // HAP spec also states that it may request packet times of 20, 30, 40, or 60.
249
+ // In practice, HAP has been seen to request 20 on LAN and 60 over LTE.
250
+ // So the RTP timestamp must scale accordingly.
251
+ // Further investigation indicates that HAP doesn't care about the actual sample rate at all,
252
+ // that's merely a suggestion. When encoding Opus, it can seemingly be an arbitrary sample rate,
253
+ // audio will work so long as the rtp timestamps are created properly: which is a construct of the sample rate
254
+ // HAP requests, and the packet time is respected,
255
+ // opus 48khz will work just fine.
256
+ rtp.header.timestamp = (firstTimestamp + audioPacketCount * 160 * audioIntervalScale) % 0xffffffff;
257
+ audioPacketCount++;
258
+ }
259
+ // encrypt the packet
260
+ const encryptedPacket = audioSrtpSession.encrypt(rtp.payload, rtp.header);
261
+ // send the encrypted packet to HomeKit
262
+ this.audioSplitter
263
+ .send(encryptedPacket, {
264
+ port: audioPort,
265
+ address: targetAddress,
266
+ })
267
+ .catch((error) => {
268
+ this.logger.error(this.cameraDevice.name, 'Failed to send audio packet', error);
269
+ });
270
+ return null;
271
+ });
272
+ }
273
+ async libfdkAacInstalledPromise() {
274
+ return doesFfmpegSupportCodec('libfdk_aac', await this.cameraDevice.getFfmpegPath())
275
+ .then((supported) => {
276
+ if (!supported) {
277
+ this.logger.error('Streaming video only - found ffmpeg, but libfdk_aac is not installed.');
278
+ }
279
+ return supported;
280
+ })
281
+ .catch(() => {
282
+ this.logger.error('Streaming video only - ffmpeg was not found.');
283
+ return false;
284
+ });
285
+ }
286
+ }
287
+ //# sourceMappingURL=sessionWrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionWrapper.js","sourceRoot":"","sources":["../../src/camera/sessionWrapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { CameraDevice, PluginLogger } from '@camera.ui/types';
2
+ import type { CameraStreamingDelegate, PrepareStreamCallback, PrepareStreamRequest, SnapshotRequest, SnapshotRequestCallback, StreamRequestCallback, StreamingRequest } from 'hap-nodejs';
3
+ import type { CameraAccessory } from './accessory.js';
4
+ export declare class StreamingDelegate implements CameraStreamingDelegate {
5
+ private cameraAccessory;
6
+ private cameraDevice;
7
+ private logger;
8
+ private sessions;
9
+ constructor(cameraAccessory: CameraAccessory, cameraDevice: CameraDevice, logger: PluginLogger);
10
+ handleSnapshotRequest(request: SnapshotRequest, callback: SnapshotRequestCallback): Promise<void>;
11
+ prepareStream(request: PrepareStreamRequest, callback: PrepareStreamCallback): Promise<void>;
12
+ handleStreamRequest(request: StreamingRequest, callback: StreamRequestCallback): Promise<void>;
13
+ }
@@ -0,0 +1,96 @@
1
+ import { readFile } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { promisify } from 'node:util';
4
+ import { StreamingSessionWrapper } from './sessionWrapper.js';
5
+ const __dirname = new URL('.', import.meta.url).pathname;
6
+ function getDurationSeconds(start) {
7
+ return (Date.now() - start) / 1000;
8
+ }
9
+ const readFileAsync = promisify(readFile);
10
+ // const offlinePath = resolve('../../media/offline.png');
11
+ const noSnapshotPath = resolve(__dirname, '../../media/noSnapshot.png');
12
+ // const privacyPath = resolve('../../media/privacy.png');
13
+ // const maxStreamsPath = resolve('../../media/maxStreams.png');
14
+ export class StreamingDelegate {
15
+ cameraAccessory;
16
+ cameraDevice;
17
+ logger;
18
+ sessions = {};
19
+ constructor(cameraAccessory, cameraDevice, logger) {
20
+ this.cameraAccessory = cameraAccessory;
21
+ this.cameraDevice = cameraDevice;
22
+ this.logger = logger;
23
+ }
24
+ async handleSnapshotRequest(request, callback) {
25
+ try {
26
+ this.logger.log(this.cameraDevice.name, 'Fetching snapshot', request);
27
+ const snapshot = await this.cameraDevice.snapshot();
28
+ let snapshotBuffer = Buffer.from(snapshot);
29
+ if (!snapshotBuffer || snapshotBuffer.length === 0) {
30
+ this.logger.log(this.cameraDevice.name, 'No snapshot available, sending offline image');
31
+ snapshotBuffer = await readFileAsync(noSnapshotPath);
32
+ }
33
+ callback(undefined, snapshotBuffer);
34
+ }
35
+ catch (error) {
36
+ this.logger.error(this.cameraDevice.name, 'Error fetching snapshot', error);
37
+ callback(error);
38
+ }
39
+ }
40
+ async prepareStream(request, callback) {
41
+ const start = Date.now();
42
+ this.logger.debug(this.cameraDevice.name, 'Preparing Stream');
43
+ try {
44
+ const streamingSession = await this.cameraDevice.createSession(this.cameraDevice.streamSource.name);
45
+ const session = new StreamingSessionWrapper(this.cameraAccessory, this.cameraDevice, streamingSession, request, start, this.logger);
46
+ this.sessions[request.sessionID] = session;
47
+ this.logger.debug(this.cameraDevice.name, `Stream Prepared (${getDurationSeconds(start)}s)`);
48
+ callback(undefined, {
49
+ audio: {
50
+ port: await session.audioSplitter.portPromise,
51
+ ssrc: session.audioSsrc,
52
+ srtp_key: session.audioSrtp.srtpKey,
53
+ srtp_salt: session.audioSrtp.srtpSalt,
54
+ },
55
+ video: {
56
+ port: await session.videoSplitter.portPromise,
57
+ ssrc: session.videoSsrc,
58
+ srtp_key: session.videoSrtp.srtpKey,
59
+ srtp_salt: session.videoSrtp.srtpSalt,
60
+ },
61
+ });
62
+ }
63
+ catch (error) {
64
+ this.logger.error(this.cameraDevice.name, `Failed to prepare stream (${getDurationSeconds(start)}s)`, error);
65
+ callback(error);
66
+ }
67
+ }
68
+ async handleStreamRequest(request, callback) {
69
+ const sessionID = request.sessionID;
70
+ const session = this.sessions[sessionID];
71
+ const requestType = request.type;
72
+ if (!session) {
73
+ callback(new Error('Cannot find session for stream ' + sessionID));
74
+ return;
75
+ }
76
+ if (requestType === "start" /* StreamRequestTypes.START */) {
77
+ this.logger.debug(this.cameraDevice.name, `Starting stream (${getDurationSeconds(session.start)}s)`);
78
+ try {
79
+ await session.activate(request);
80
+ }
81
+ catch (error) {
82
+ this.logger.error(this.cameraDevice.name, 'Failed to starting stream', error);
83
+ callback(new Error('Failed to activate stream'));
84
+ return;
85
+ }
86
+ this.logger.log(this.cameraDevice.name, `Streaming started (${getDurationSeconds(session.start)}s)`);
87
+ }
88
+ else if (requestType === "stop" /* StreamRequestTypes.STOP */) {
89
+ this.logger.log(this.cameraDevice.name, 'Stopped Live Stream');
90
+ session.stop();
91
+ delete this.sessions[sessionID];
92
+ }
93
+ callback();
94
+ }
95
+ }
96
+ //# sourceMappingURL=streamingDelegate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamingDelegate.js","sourceRoot":"","sources":["../../src/camera/streamingDelegate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAc9D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;AAEzD,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAC1C,0DAA0D;AAC1D,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE,4BAA4B,CAAC,CAAC;AACxE,0DAA0D;AAC1D,gEAAgE;AAEhE,MAAM,OAAO,iBAAiB;IACpB,eAAe,CAAkB;IACjC,YAAY,CAAe;IAC3B,MAAM,CAAe;IAErB,QAAQ,GAAsD,EAAE,CAAC;IAEzE,YAAY,eAAgC,EAAE,YAA0B,EAAE,MAAoB;QAC5F,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEM,KAAK,CAAC,qBAAqB,CAAC,OAAwB,EAAE,QAAiC;QAC5F,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,CAAC,CAAC;YAEtE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;YACpD,IAAI,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAE3C,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,8CAA8C,CAAC,CAAC;gBACxF,cAAc,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,CAAC;YACvD,CAAC;YAED,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAC5E,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,OAA6B,EAAE,QAA+B;QACvF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;QAE9D,IAAI,CAAC;YACH,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAEpG,MAAM,OAAO,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACpI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC;YAE3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,oBAAoB,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAE7F,QAAQ,CAAC,SAAS,EAAE;gBAClB,KAAK,EAAE;oBACL,IAAI,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,WAAW;oBAC7C,IAAI,EAAE,OAAO,CAAC,SAAS;oBACvB,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,OAAO;oBACnC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,QAAQ;iBACtC;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,WAAW;oBAC7C,IAAI,EAAE,OAAO,CAAC,SAAS;oBACvB,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,OAAO;oBACnC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,QAAQ;iBACtC;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,6BAA6B,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7G,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAAC,OAAyB,EAAE,QAA+B;QACzF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;QAEjC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,KAAK,CAAC,iCAAiC,GAAG,SAAS,CAAC,CAAC,CAAC;YACnE,OAAO;QACT,CAAC;QAED,IAAI,WAAW,2CAA6B,EAAE,CAAC;YAC7C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,oBAAoB,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrG,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,2BAA2B,EAAE,KAAK,CAAC,CAAC;gBAC9E,QAAQ,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC;gBACjD,OAAO;YACT,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,sBAAsB,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvG,CAAC;aAAM,IAAI,WAAW,yCAA4B,EAAE,CAAC;YACnD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAED,QAAQ,EAAE,CAAC;IACb,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ import type { CameraDevice, PluginLogger } from '@camera.ui/types';
2
+ import type { Accessory } from 'hap-nodejs';
3
+ import type { MP4Atom } from '../types.js';
4
+ export declare class MP4StreamingServer {
5
+ debugMode: boolean;
6
+ destroyed: boolean;
7
+ private logger;
8
+ private accessory;
9
+ private cameraDevice;
10
+ private server?;
11
+ private socket?;
12
+ private childProcess?;
13
+ private connectPromise?;
14
+ private connectResolve?;
15
+ private connectReject?;
16
+ private isRemoteServer;
17
+ constructor(logger: PluginLogger, accessory: Accessory, cameraDevice: CameraDevice);
18
+ createServer(ffmpegPath: string, ffmpegInput: Array<string>, videoOutputArgs: Array<string>, audioOutputArgs: Array<string>): Promise<void>;
19
+ connectToServer(prebufferUrl: string): Promise<void>;
20
+ destroy(): Promise<void>;
21
+ generator(): AsyncGenerator<MP4Atom>;
22
+ private handleConnection;
23
+ private read;
24
+ }
@@ -0,0 +1,143 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { once } from 'node:events';
3
+ import { Socket, createServer } from 'node:net';
4
+ export class MP4StreamingServer {
5
+ debugMode = false;
6
+ destroyed = false;
7
+ logger;
8
+ accessory;
9
+ cameraDevice;
10
+ server;
11
+ socket;
12
+ childProcess;
13
+ connectPromise;
14
+ connectResolve;
15
+ connectReject;
16
+ isRemoteServer = false;
17
+ constructor(logger, accessory, cameraDevice) {
18
+ this.logger = logger;
19
+ this.accessory = accessory;
20
+ this.cameraDevice = cameraDevice;
21
+ }
22
+ async createServer(ffmpegPath, ffmpegInput, videoOutputArgs, audioOutputArgs) {
23
+ this.isRemoteServer = false;
24
+ this.connectPromise = new Promise((resolve, reject) => {
25
+ this.connectResolve = resolve;
26
+ this.connectReject = reject;
27
+ });
28
+ this.server = createServer(this.handleConnection.bind(this));
29
+ const ffmpeg = ffmpegPath;
30
+ const args = [
31
+ ...ffmpegInput,
32
+ ...videoOutputArgs,
33
+ ...audioOutputArgs,
34
+ '-fflags',
35
+ '+genpts',
36
+ '-reset_timestamps',
37
+ '1',
38
+ '-movflags',
39
+ 'frag_keyframe+empty_moov+default_base_moof+skip_sidx+skip_trailer',
40
+ '-f',
41
+ 'mp4',
42
+ ];
43
+ const promise = once(this.server, 'listening');
44
+ this.server.listen(); // listen on random port
45
+ await promise;
46
+ if (this.destroyed) {
47
+ return;
48
+ }
49
+ const port = this.server.address().port;
50
+ args.push('tcp://127.0.0.1:' + port);
51
+ this.logger.debug(this.cameraDevice.name, 'Recording command:', args.join(' '));
52
+ this.childProcess = spawn(ffmpeg, args, { env: process.env, stdio: this.debugMode ? 'pipe' : 'ignore' });
53
+ if (this.debugMode) {
54
+ this.childProcess.stdout?.on('data', (data) => this.logger.debug(this.cameraDevice.name, data.toString()));
55
+ this.childProcess.stderr?.on('data', (data) => this.logger.debug(this.cameraDevice.name, data.toString()));
56
+ }
57
+ }
58
+ async connectToServer(prebufferUrl) {
59
+ this.isRemoteServer = true;
60
+ this.connectPromise = new Promise((resolve, reject) => {
61
+ this.connectResolve = resolve;
62
+ this.connectReject = reject;
63
+ });
64
+ const socketUrl = new URL(prebufferUrl);
65
+ const socket = new Socket();
66
+ this.handleConnection(socket);
67
+ const promise = once(socket, 'connect');
68
+ socket.connect(parseInt(socketUrl.port), socketUrl.hostname);
69
+ await promise;
70
+ this.logger.debug(this.cameraDevice.name, 'Recording command: Remote server');
71
+ }
72
+ async destroy() {
73
+ this.socket?.destroy();
74
+ this.childProcess?.kill('SIGKILL');
75
+ this.server = undefined;
76
+ this.socket = undefined;
77
+ this.childProcess = undefined;
78
+ if (this.connectPromise) {
79
+ this.connectReject?.(new Error('Destroyed'));
80
+ this.connectPromise = undefined;
81
+ }
82
+ this.destroyed = true;
83
+ }
84
+ async *generator() {
85
+ await this.connectPromise;
86
+ this.connectPromise = undefined;
87
+ if (!this.socket || (!this.isRemoteServer && !this.childProcess)) {
88
+ throw new Error('Unexpected state!');
89
+ }
90
+ while (true) {
91
+ const header = await this.read(8);
92
+ const length = header.readInt32BE(0) - 8;
93
+ const type = header.subarray(4).toString();
94
+ const data = await this.read(length);
95
+ yield {
96
+ header: header,
97
+ length: length,
98
+ type: type,
99
+ data: data,
100
+ };
101
+ }
102
+ }
103
+ handleConnection(socket) {
104
+ this.server?.close(); // don't accept any further clients
105
+ this.socket = socket;
106
+ this.connectResolve?.();
107
+ }
108
+ async read(length) {
109
+ if (!this.socket) {
110
+ throw Error('FFMPEG tried reading from closed socket!');
111
+ }
112
+ if (!length) {
113
+ return Buffer.alloc(0);
114
+ }
115
+ const value = this.socket.read(length);
116
+ if (value) {
117
+ return value;
118
+ }
119
+ return new Promise((resolve, reject) => {
120
+ const readHandler = () => {
121
+ const value = this.socket.read(length);
122
+ if (value) {
123
+ cleanup();
124
+ resolve(value);
125
+ }
126
+ };
127
+ const endHandler = () => {
128
+ cleanup();
129
+ reject(new Error(`FFMPEG socket closed during read for ${length} bytes!`));
130
+ };
131
+ const cleanup = () => {
132
+ this.socket?.removeListener('readable', readHandler);
133
+ this.socket?.removeListener('close', endHandler);
134
+ };
135
+ if (!this.socket) {
136
+ throw new Error('FFMPEG socket is closed now!');
137
+ }
138
+ this.socket.on('readable', readHandler);
139
+ this.socket.on('close', endHandler);
140
+ });
141
+ }
142
+ }
143
+ //# sourceMappingURL=streamingServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamingServer.js","sourceRoot":"","sources":["../../src/camera/streamingServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/crypto.js ADDED
@@ -0,0 +1,29 @@
1
+ import chacha from 'chacha';
2
+ import crypto from 'node:crypto';
3
+ if (!crypto.getCiphers().includes('chacha20-poly1305')) {
4
+ const originalGetCiphers = crypto.getCiphers;
5
+ const originalCreateCipheriv = crypto.createCipheriv;
6
+ const originalCreateDecipheriv = crypto.createDecipheriv;
7
+ crypto.getCiphers = () => {
8
+ const ciphers = originalGetCiphers();
9
+ ciphers.push('chacha20-poly1305');
10
+ return ciphers;
11
+ };
12
+ crypto.createCipheriv = (algorithm, key, iv, options) => {
13
+ if (algorithm !== 'chacha20-poly1305') {
14
+ return originalCreateCipheriv(algorithm, key, iv, options);
15
+ }
16
+ else {
17
+ return chacha.createCipher(key, iv);
18
+ }
19
+ };
20
+ crypto.createDecipheriv = (algorithm, key, iv, options) => {
21
+ if (algorithm !== 'chacha20-poly1305') {
22
+ return originalCreateDecipheriv(algorithm, key, iv, options);
23
+ }
24
+ else {
25
+ return chacha.createDecipher(key, iv);
26
+ }
27
+ };
28
+ }
29
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;IACvD,MAAM,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC;IAC7C,MAAM,sBAAsB,GAAG,MAAM,CAAC,cAAc,CAAC;IACrD,MAAM,wBAAwB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAEzD,MAAM,CAAC,UAAU,GAAG,GAAa,EAAE;QACjC,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,CAAC,cAAc,GAAG,CAAC,SAAc,EAAE,GAAQ,EAAE,EAAO,EAAE,OAAY,EAAE,EAAE;QAC1E,IAAI,SAAS,KAAK,mBAAmB,EAAE,CAAC;YACtC,OAAO,sBAAsB,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,gBAAgB,GAAG,CAAC,SAAc,EAAE,GAAQ,EAAE,EAAO,EAAE,OAAa,EAAE,EAAE;QAC7E,IAAI,SAAS,KAAK,mBAAmB,EAAE,CAAC;YACtC,OAAO,wBAAwB,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}