homebridge-ring-hksv 14.3.5 → 14.3.7

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 CHANGED
@@ -31,6 +31,9 @@ Big thanks to Dustin and all upstream contributors. This fork reuses and extends
31
31
  | `hksvPrebufferLengthMs` | HKSV prebuffer duration (minimum 4000ms) |
32
32
  | `hksvFragmentLengthMs` | HKSV fragment duration target |
33
33
  | `hksvMaxRecordingSeconds` | Optional safety cap for a recording session |
34
+ | `hksvVideoBitrateKbps` / `hksvVideoMaxBitrateKbps` / `hksvVideoBufferSizeKbps` | HKSV recording bitrate controls for improving fast-motion quality |
35
+ | `hksvVideoCrf` / `hksvVideoPreset` | Optional libx264 quality and CPU tuning controls |
36
+ | `hksvVideoKeyframeInterval` | HKSV recording keyframe interval |
34
37
  | `homeKitAccessoryTag` | Appends a tag to accessory names and HomeKit IDs so the same Ring device can be exposed as a distinct HomeKit accessory for debugging/testing |
35
38
  | `cameraVideoCodec` | Preferred H.264 encoder (`h264_videotoolbox` or `libx264`) |
36
39
  | `hideDoorbellSwitch` / `hideCameraMotionSensor` / `hideCameraSirenSwitch` | Hides specific HomeKit-exposed services |
@@ -86,6 +89,12 @@ HKSV support is experimental and actively evolving. Behavior may vary by camera
86
89
  I currently am able to run 3 cameras with HKSV enabled on a Homebridge instance ran on a M4 Mac Mini 32GB of RAM.
87
90
  Please report your experience and setup details to help improve support.
88
91
 
92
+ For fast-motion pixelation or stuttering in HKSV recordings, try increasing
93
+ `hksvVideoBitrateKbps` first. On Apple Silicon Macs,
94
+ `cameraVideoCodec: "h264_videotoolbox"` can reduce CPU load by using hardware
95
+ encoding. A good starting point is 4000-6000 kbps target bitrate, 8000-12000
96
+ kbps max bitrate, and the default keyframe interval of 30.
97
+
89
98
  ### Minimum specifications for HKSV:
90
99
  [TBD - will be added as more users test and report their setups]
91
100
 
@@ -53,6 +53,86 @@
53
53
  "maximum": 300,
54
54
  "description": "Optional safety cap for a single HKSV recording stream duration."
55
55
  },
56
+ "hksvVideoBitrateKbps": {
57
+ "title": "HKSV Video Bitrate (kbps)",
58
+ "type": "integer",
59
+ "minimum": 256,
60
+ "maximum": 12000,
61
+ "default": 3000,
62
+ "description": "Target video bitrate for HKSV recording transcodes. Increase this first if fast motion becomes blocky or pixelated. 4000-6000 is a good starting range for wired cameras."
63
+ },
64
+ "hksvVideoMaxBitrateKbps": {
65
+ "title": "HKSV Max Video Bitrate (kbps)",
66
+ "type": "integer",
67
+ "minimum": 256,
68
+ "maximum": 20000,
69
+ "description": "Maximum burst bitrate for HKSV recording transcodes. Defaults to 2x the target bitrate. A practical starting range is 8000-12000 when target bitrate is 4000-6000."
70
+ },
71
+ "hksvVideoBufferSizeKbps": {
72
+ "title": "HKSV Video Buffer Size (kbps)",
73
+ "type": "integer",
74
+ "minimum": 256,
75
+ "maximum": 40000,
76
+ "description": "FFmpeg VBV buffer size for HKSV recording transcodes. Defaults to 2x the max video bitrate. Leave unset unless you are tuning bitrate stability."
77
+ },
78
+ "hksvVideoCrf": {
79
+ "title": "HKSV x264 Quality (CRF)",
80
+ "type": "integer",
81
+ "minimum": 18,
82
+ "maximum": 35,
83
+ "description": "Optional libx264 quality value. Lower values improve quality and use more bitrate/CPU. Try 20-23 if you stay on libx264. Ignored when using VideoToolbox."
84
+ },
85
+ "hksvVideoKeyframeInterval": {
86
+ "title": "HKSV Keyframe Interval",
87
+ "type": "integer",
88
+ "minimum": 5,
89
+ "maximum": 240,
90
+ "default": 30,
91
+ "description": "Maximum number of frames between video keyframes in HKSV recordings. 30 is the recommended default. Shorter intervals can improve fragmenting at the cost of bitrate."
92
+ },
93
+ "hksvVideoPreset": {
94
+ "title": "HKSV x264 Preset",
95
+ "type": "string",
96
+ "description": "libx264 speed/quality preset for HKSV recordings. veryfast is the recommended default. Move toward fast or medium for quality, or superfast for lower CPU. Ignored when using VideoToolbox.",
97
+ "oneOf": [
98
+ {
99
+ "title": "ultrafast",
100
+ "enum": ["ultrafast"]
101
+ },
102
+ {
103
+ "title": "superfast",
104
+ "enum": ["superfast"]
105
+ },
106
+ {
107
+ "title": "veryfast",
108
+ "enum": ["veryfast"]
109
+ },
110
+ {
111
+ "title": "faster",
112
+ "enum": ["faster"]
113
+ },
114
+ {
115
+ "title": "fast",
116
+ "enum": ["fast"]
117
+ },
118
+ {
119
+ "title": "medium",
120
+ "enum": ["medium"]
121
+ },
122
+ {
123
+ "title": "slow",
124
+ "enum": ["slow"]
125
+ },
126
+ {
127
+ "title": "slower",
128
+ "enum": ["slower"]
129
+ },
130
+ {
131
+ "title": "veryslow",
132
+ "enum": ["veryslow"]
133
+ }
134
+ ]
135
+ },
56
136
  "homeKitAccessoryTag": {
57
137
  "title": "HomeKit Accessory Tag",
58
138
  "type": "string",
@@ -61,7 +141,7 @@
61
141
  "cameraVideoCodec": {
62
142
  "title": "Camera Video Codec",
63
143
  "type": "string",
64
- "description": "Preferred ffmpeg H.264 encoder for camera paths.",
144
+ "description": "Preferred FFmpeg H.264 encoder for HKSV recording transcodes. On Apple Silicon or newer Intel Macs, h264_videotoolbox is the recommended first choice because it uses hardware acceleration.",
65
145
  "oneOf": [
66
146
  {
67
147
  "title": "h264_videotoolbox",
@@ -215,6 +295,12 @@
215
295
  "hksvPrebufferLengthMs",
216
296
  "hksvFragmentLengthMs",
217
297
  "hksvMaxRecordingSeconds",
298
+ "hksvVideoBitrateKbps",
299
+ "hksvVideoMaxBitrateKbps",
300
+ "hksvVideoBufferSizeKbps",
301
+ "hksvVideoCrf",
302
+ "hksvVideoKeyframeInterval",
303
+ "hksvVideoPreset",
218
304
  "homeKitAccessoryTag",
219
305
  "cameraVideoCodec",
220
306
  "hideLightGroups",
@@ -23,6 +23,12 @@ function getSessionConfig(srtpOptions) {
23
23
  profile: 1,
24
24
  };
25
25
  }
26
+ function getIntegerConfigValue(value, defaultValue, min, max) {
27
+ if (!Number.isFinite(value)) {
28
+ return defaultValue;
29
+ }
30
+ return Math.min(Math.max(Math.round(value), min), max);
31
+ }
26
32
  function* parseMp4Boxes(data) {
27
33
  let offset = 0;
28
34
  while (offset + 8 <= data.length) {
@@ -254,6 +260,7 @@ export class CameraSource {
254
260
  sessions = {};
255
261
  cachedSnapshot;
256
262
  ringCamera;
263
+ config;
257
264
  recordingActive = false;
258
265
  recordingConfiguration;
259
266
  closedRecordingStreams = new Set();
@@ -261,6 +268,7 @@ export class CameraSource {
261
268
  activeRecordingSessions = new Map();
262
269
  constructor(ringCamera, config) {
263
270
  this.ringCamera = ringCamera;
271
+ this.config = config;
264
272
  const enableHksv = config.enableHksv && !(config.disableHksvOnBattery && ringCamera.hasBattery);
265
273
  const controllerOptions = {
266
274
  cameraStreamCount: enableHksv ? 1 : 10,
@@ -358,6 +366,33 @@ export class CameraSource {
358
366
  }
359
367
  this.controller = new hap.CameraController(controllerOptions);
360
368
  }
369
+ getHksvVideoArguments() {
370
+ const { cameraVideoCodec = 'libx264', hksvVideoCrf, hksvVideoPreset = 'veryfast', } = this.config, bitrateKbps = getIntegerConfigValue(this.config.hksvVideoBitrateKbps, 3000, 256, 12000), maxBitrateKbps = getIntegerConfigValue(this.config.hksvVideoMaxBitrateKbps, bitrateKbps * 2, bitrateKbps, 20000), bufferSizeKbps = getIntegerConfigValue(this.config.hksvVideoBufferSizeKbps, maxBitrateKbps * 2, maxBitrateKbps, 40000), keyframeInterval = getIntegerConfigValue(this.config.hksvVideoKeyframeInterval, 30, 5, 240), videoArguments = [
371
+ '-vcodec',
372
+ cameraVideoCodec,
373
+ '-b:v',
374
+ `${bitrateKbps}k`,
375
+ '-maxrate',
376
+ `${maxBitrateKbps}k`,
377
+ '-bufsize',
378
+ `${bufferSizeKbps}k`,
379
+ '-pix_fmt',
380
+ 'yuv420p',
381
+ '-profile:v',
382
+ 'baseline',
383
+ '-level:v',
384
+ '3.1',
385
+ '-g',
386
+ `${keyframeInterval}`,
387
+ ];
388
+ if (cameraVideoCodec === 'libx264') {
389
+ videoArguments.push('-preset', hksvVideoPreset, '-tune', 'zerolatency', '-keyint_min', `${keyframeInterval}`, '-sc_threshold', '0');
390
+ if (Number.isFinite(hksvVideoCrf)) {
391
+ videoArguments.push('-crf', `${getIntegerConfigValue(hksvVideoCrf, 23, 18, 35)}`);
392
+ }
393
+ }
394
+ return videoArguments;
395
+ }
361
396
  previousLoadSnapshotPromise;
362
397
  async loadSnapshot(imageUuid) {
363
398
  // cache a promise of the snapshot load
@@ -533,32 +568,21 @@ export class CameraSource {
533
568
  this.activeRecordingSessions.set(streamId, closeSession);
534
569
  let liveCall;
535
570
  let keyFrameTimer;
571
+ let maxRecordingTimer;
536
572
  try {
537
573
  liveCall = await this.ringCamera.startLiveCall();
538
574
  liveCall.onCallEnded.pipe(take(1)).subscribe(() => {
539
575
  closeSession();
540
576
  });
577
+ const maxRecordingSeconds = getIntegerConfigValue(this.config.hksvMaxRecordingSeconds, 0, 0, 300);
578
+ if (maxRecordingSeconds) {
579
+ maxRecordingTimer = setTimeout(() => {
580
+ logInfo(`HKSV recording stream reached max duration for ${this.ringCamera.name} (streamId=${streamId}, maxSeconds=${maxRecordingSeconds})`);
581
+ closeSession();
582
+ }, maxRecordingSeconds * 1000);
583
+ }
541
584
  await liveCall.startTranscoding({
542
- video: [
543
- '-vcodec',
544
- 'libx264',
545
- '-preset',
546
- 'veryfast',
547
- '-tune',
548
- 'zerolatency',
549
- '-pix_fmt',
550
- 'yuv420p',
551
- '-profile:v',
552
- 'baseline',
553
- '-level:v',
554
- '3.1',
555
- '-g',
556
- '30',
557
- '-keyint_min',
558
- '30',
559
- '-sc_threshold',
560
- '0',
561
- ],
585
+ video: this.getHksvVideoArguments(),
562
586
  output: [
563
587
  '-movflags',
564
588
  'frag_keyframe+empty_moov+default_base_moof',
@@ -650,6 +674,9 @@ export class CameraSource {
650
674
  if (keyFrameTimer) {
651
675
  clearInterval(keyFrameTimer);
652
676
  }
677
+ if (maxRecordingTimer) {
678
+ clearTimeout(maxRecordingTimer);
679
+ }
653
680
  if (liveCall) {
654
681
  liveCall.stop();
655
682
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-ring-hksv",
3
3
  "displayName": "Homebridge Ring HKSV",
4
- "version": "14.3.5",
4
+ "version": "14.3.7",
5
5
  "description": "Homebridge plugin for Ring devices with HomeKit Secure Video support",
6
6
  "type": "module",
7
7
  "main": "./lib/index.js",