homebridge-unifi-protect 7.14.0 → 7.16.0
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/dist/devices/protect-camera-package.d.ts +2 -2
- package/dist/devices/protect-camera-package.js +1 -1
- package/dist/devices/protect-camera-package.js.map +1 -1
- package/dist/devices/protect-camera.d.ts +5 -5
- package/dist/devices/protect-camera.js +40 -17
- package/dist/devices/protect-camera.js.map +1 -1
- package/dist/devices/protect-chime.d.ts +3 -3
- package/dist/devices/protect-device.d.ts +8 -7
- package/dist/devices/protect-device.js.map +1 -1
- package/dist/devices/protect-doorbell.d.ts +3 -3
- package/dist/devices/protect-doorbell.js +2 -2
- package/dist/devices/protect-doorbell.js.map +1 -1
- package/dist/devices/protect-light.d.ts +3 -3
- package/dist/devices/protect-light.js +2 -2
- package/dist/devices/protect-light.js.map +1 -1
- package/dist/devices/protect-liveviews.d.ts +1 -1
- package/dist/devices/protect-liveviews.js.map +1 -1
- package/dist/devices/protect-nvr-systeminfo.d.ts +1 -1
- package/dist/devices/protect-nvr-systeminfo.js.map +1 -1
- package/dist/devices/protect-securitysystem.d.ts +2 -2
- package/dist/devices/protect-sensor.d.ts +3 -3
- package/dist/devices/protect-viewer.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/protect-events.d.ts +4 -4
- package/dist/protect-events.js.map +1 -1
- package/dist/protect-livestream.d.ts +5 -4
- package/dist/protect-livestream.js +29 -15
- package/dist/protect-livestream.js.map +1 -1
- package/dist/protect-nvr.d.ts +7 -6
- package/dist/protect-nvr.js +7 -5
- package/dist/protect-nvr.js.map +1 -1
- package/dist/protect-options.d.ts +1 -1
- package/dist/protect-options.js +2 -1
- package/dist/protect-options.js.map +1 -1
- package/dist/protect-platform.d.ts +3 -7
- package/dist/protect-platform.js +2 -44
- package/dist/protect-platform.js.map +1 -1
- package/dist/protect-record.d.ts +5 -3
- package/dist/protect-record.js +11 -8
- package/dist/protect-record.js.map +1 -1
- package/dist/protect-snapshot.d.ts +4 -4
- package/dist/protect-snapshot.js +8 -9
- package/dist/protect-snapshot.js.map +1 -1
- package/dist/protect-stream.d.ts +6 -6
- package/dist/protect-stream.js +101 -58
- package/dist/protect-stream.js.map +1 -1
- package/dist/protect-timeshift.d.ts +3 -3
- package/dist/protect-timeshift.js +1 -1
- package/dist/protect-timeshift.js.map +1 -1
- package/dist/protect-types.d.ts +2 -2
- package/dist/settings.d.ts +0 -2
- package/dist/settings.js +0 -4
- package/dist/settings.js.map +1 -1
- package/homebridge-ui/public/lib/featureoptions.js +65 -6
- package/homebridge-ui/public/lib/featureoptions.js.map +1 -1
- package/homebridge-ui/public/lib/webUi-featureoptions.mjs +4 -4
- package/package.json +6 -6
- package/dist/ffmpeg/index.d.ts +0 -6
- package/dist/ffmpeg/index.js +0 -11
- package/dist/ffmpeg/index.js.map +0 -1
- package/dist/ffmpeg/protect-ffmpeg-codecs.d.ts +0 -22
- package/dist/ffmpeg/protect-ffmpeg-codecs.js +0 -189
- package/dist/ffmpeg/protect-ffmpeg-codecs.js.map +0 -1
- package/dist/ffmpeg/protect-ffmpeg-exec.d.ts +0 -15
- package/dist/ffmpeg/protect-ffmpeg-exec.js +0 -58
- package/dist/ffmpeg/protect-ffmpeg-exec.js.map +0 -1
- package/dist/ffmpeg/protect-ffmpeg-options.d.ts +0 -33
- package/dist/ffmpeg/protect-ffmpeg-options.js +0 -555
- package/dist/ffmpeg/protect-ffmpeg-options.js.map +0 -1
- package/dist/ffmpeg/protect-ffmpeg-record.d.ts +0 -15
- package/dist/ffmpeg/protect-ffmpeg-record.js +0 -246
- package/dist/ffmpeg/protect-ffmpeg-record.js.map +0 -1
- package/dist/ffmpeg/protect-ffmpeg-stream.d.ts +0 -17
- package/dist/ffmpeg/protect-ffmpeg-stream.js +0 -102
- package/dist/ffmpeg/protect-ffmpeg-stream.js.map +0 -1
- package/dist/ffmpeg/protect-ffmpeg.d.ts +0 -35
- package/dist/ffmpeg/protect-ffmpeg.js +0 -238
- package/dist/ffmpeg/protect-ffmpeg.js.map +0 -1
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
/* Copyright(C) 2017-2025, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
|
-
*
|
|
3
|
-
* protect-ffmpeg-record.ts: Provide FFmpeg process control to support HomeKit Secure Video.
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
import { PROTECT_HKSV_IDR_INTERVAL, PROTECT_HKSV_TIMEOUT } from "../settings.js";
|
|
7
|
-
import { FfmpegProcess } from "./protect-ffmpeg.js";
|
|
8
|
-
import { once } from "node:events";
|
|
9
|
-
import { runWithTimeout } from "homebridge-plugin-utils";
|
|
10
|
-
// FFmpeg HomeKit Streaming Video recording process management.
|
|
11
|
-
export class FfmpegRecordingProcess extends FfmpegProcess {
|
|
12
|
-
isLoggingErrors;
|
|
13
|
-
isTimedOut;
|
|
14
|
-
recordingBuffer;
|
|
15
|
-
recordingConfig;
|
|
16
|
-
// Create a new FFmpeg process instance.
|
|
17
|
-
constructor(protectCamera, recordingConfig, rtspEntry, isAudioActive) {
|
|
18
|
-
// Initialize our parent.
|
|
19
|
-
super(protectCamera);
|
|
20
|
-
// We want to log errors when they occur.
|
|
21
|
-
this.isLoggingErrors = true;
|
|
22
|
-
// Initialize our recording buffer.
|
|
23
|
-
this.recordingBuffer = [];
|
|
24
|
-
// Initialize our state.
|
|
25
|
-
this.isTimedOut = false;
|
|
26
|
-
// Save our recording configuration.
|
|
27
|
-
this.recordingConfig = recordingConfig;
|
|
28
|
-
// Configure our video parameters for our input:
|
|
29
|
-
//
|
|
30
|
-
// -hide_banner Suppress printing the startup banner in FFmpeg.
|
|
31
|
-
// -nostats Suppress printing progress reports while encoding in FFmpeg.
|
|
32
|
-
// -fflags flags Set the format flags to generate a presentation timestamp if it's missing and discard any corrupt packets rather than exit.
|
|
33
|
-
// -err_detect ignore_err Ignore decoding errors and continue rather than exit.
|
|
34
|
-
// -probesize number How many bytes should be analyzed for stream information. Use the size of the timeshift buffer or our configured defaults.
|
|
35
|
-
// -r fps Set the input frame rate for the video stream.
|
|
36
|
-
// -f mp4 Tell FFmpeg that it should expect an MP4-encoded input stream.
|
|
37
|
-
// -i pipe:0 Use standard input to get video data.
|
|
38
|
-
// -ss Fast forward to where HKSV is expecting us to be for a recording event.
|
|
39
|
-
this.commandLineArgs = [
|
|
40
|
-
"-hide_banner",
|
|
41
|
-
"-nostats",
|
|
42
|
-
"-fflags", "+discardcorrupt+genpts",
|
|
43
|
-
"-err_detect", "ignore_err",
|
|
44
|
-
"-probesize", (protectCamera.stream.hksv?.timeshift.buffer?.length ?? protectCamera.stream.probesize).toString(),
|
|
45
|
-
"-r", rtspEntry.channel.fps.toString(),
|
|
46
|
-
"-f", "mp4",
|
|
47
|
-
"-i", "pipe:0",
|
|
48
|
-
"-ss", Math.max((protectCamera.stream.hksv?.timeshift.time ?? 0) - recordingConfig.prebufferLength, 0).toString() + "ms"
|
|
49
|
-
];
|
|
50
|
-
// Configure our recording options for the video stream:
|
|
51
|
-
//
|
|
52
|
-
// -map 0:v:0 Selects the first available video track from the stream. Protect actually maps audio
|
|
53
|
-
// and video tracks in opposite locations from where FFmpeg typically expects them. This
|
|
54
|
-
// setting is a more general solution than naming the track locations directly in case
|
|
55
|
-
// Protect changes this in the future.
|
|
56
|
-
// Yes, we included these above as well: they need to be included for every I/O stream to
|
|
57
|
-
// maximize effectiveness it seems.
|
|
58
|
-
// -movflags flags In the generated fMP4 stream: start a new fragment at each keyframe, write a blank MOOV box, and avoid writing absolute offsets.
|
|
59
|
-
// -reset_timestamps Reset timestamps at the beginning of each segment.
|
|
60
|
-
// -metadata Set the metadata to the name of the camera to distinguish between FFmpeg sessions.
|
|
61
|
-
this.commandLineArgs.push("-map", "0:v:0", ...protectCamera.stream.ffmpegOptions.recordEncoder({
|
|
62
|
-
bitrate: recordingConfig.videoCodec.parameters.bitRate,
|
|
63
|
-
fps: recordingConfig.videoCodec.resolution[2],
|
|
64
|
-
height: recordingConfig.videoCodec.resolution[1],
|
|
65
|
-
idrInterval: PROTECT_HKSV_IDR_INTERVAL,
|
|
66
|
-
inputFps: rtspEntry.channel.fps,
|
|
67
|
-
level: recordingConfig.videoCodec.parameters.level,
|
|
68
|
-
profile: recordingConfig.videoCodec.parameters.profile,
|
|
69
|
-
width: recordingConfig.videoCodec.resolution[0]
|
|
70
|
-
}), "-movflags", "frag_keyframe+empty_moov+default_base_moof", "-reset_timestamps", "1", "-metadata", "comment=" + protectCamera.accessoryName);
|
|
71
|
-
if (isAudioActive) {
|
|
72
|
-
// Configure the audio portion of the command line. Options we use are:
|
|
73
|
-
//
|
|
74
|
-
// -map 0:a:0? Selects the first available audio track from the stream, if it exists. Protect actually maps audio and video tracks in opposite
|
|
75
|
-
// locations from where FFmpeg typically expects them. This setting is a more general solution than naming the track locations directly
|
|
76
|
-
// in case Protect changes this in the future.
|
|
77
|
-
// -acodec copy Copy the stream without reencoding it.
|
|
78
|
-
this.commandLineArgs.push("-map", "0:a:0?", "-acodec", "copy");
|
|
79
|
-
}
|
|
80
|
-
// Configure our video parameters for outputting our final stream:
|
|
81
|
-
//
|
|
82
|
-
// -f mp4 Tell ffmpeg that it should create an MP4-encoded output stream.
|
|
83
|
-
// pipe:1 Output the stream to standard output.
|
|
84
|
-
this.commandLineArgs.push("-f", "mp4", "pipe:1");
|
|
85
|
-
// Additional logging, but only if we're debugging.
|
|
86
|
-
if (protectCamera.platform.verboseFfmpeg) {
|
|
87
|
-
this.commandLineArgs.unshift("-loglevel", "level+verbose");
|
|
88
|
-
}
|
|
89
|
-
// Start the FFmpeg session.
|
|
90
|
-
this.start();
|
|
91
|
-
}
|
|
92
|
-
// Prepare and start our FFmpeg process.
|
|
93
|
-
configureProcess() {
|
|
94
|
-
let dataListener;
|
|
95
|
-
// Call our parent to get started.
|
|
96
|
-
super.configureProcess();
|
|
97
|
-
// Initialize our variables that we need to process incoming FFmpeg packets.
|
|
98
|
-
let header = Buffer.alloc(0);
|
|
99
|
-
let bufferRemaining = Buffer.alloc(0);
|
|
100
|
-
let dataLength = 0;
|
|
101
|
-
let type = "";
|
|
102
|
-
// Process FFmpeg output and parse out the fMP4 stream it's generating for HomeKit Secure Video.
|
|
103
|
-
this.process?.stdout.on("data", dataListener = (buffer) => {
|
|
104
|
-
// If we have anything left from the last buffer we processed, prepend it to this buffer.
|
|
105
|
-
if (bufferRemaining.length > 0) {
|
|
106
|
-
buffer = Buffer.concat([bufferRemaining, buffer]);
|
|
107
|
-
bufferRemaining = Buffer.alloc(0);
|
|
108
|
-
}
|
|
109
|
-
let offset = 0;
|
|
110
|
-
// FFmpeg is outputting an fMP4 stream that's suitable for HomeKit Secure Video. However, we can't just pass this stream directly back to HomeKit since we're using
|
|
111
|
-
// a generator-based API to send packets back to HKSV. Here, we take on the task of parsing the fMP4 stream that's being generated and split it up into the MP4
|
|
112
|
-
// boxes that HAP-NodeJS is ultimately expecting.
|
|
113
|
-
for (;;) {
|
|
114
|
-
let data;
|
|
115
|
-
// The MP4 container format is well-documented and designed around the concept of boxes. A box (or atom as they used to be called) is at the center of an MP4
|
|
116
|
-
// container. It's composed of an 8-byte header, followed by the data payload it carries.
|
|
117
|
-
// No existing header, let's start a new box.
|
|
118
|
-
if (!header.length) {
|
|
119
|
-
// Grab the header. The first four bytes represents the length of the entire box. Second four bytes represent the box type.
|
|
120
|
-
header = buffer.slice(0, 8);
|
|
121
|
-
// Now we retrieve the length of the box.
|
|
122
|
-
dataLength = header.readUInt32BE(0);
|
|
123
|
-
// Get the type of the box. This is always a string and has a funky history to it that makes for an interesting read!
|
|
124
|
-
type = header.slice(4).toString();
|
|
125
|
-
// Finally, we get the data portion of the box.
|
|
126
|
-
data = buffer.slice(8, dataLength);
|
|
127
|
-
// Mark our data offset so we account for the length of the data header and subtract it from the overall length to capture just the data portion.
|
|
128
|
-
dataLength -= offset = 8;
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
// Grab the data from our buffer.
|
|
132
|
-
data = buffer.slice(0, dataLength);
|
|
133
|
-
offset = 0;
|
|
134
|
-
}
|
|
135
|
-
// If we don't have enough data in this buffer, save what we have for the next buffer we see and append it there.
|
|
136
|
-
if (data.length < dataLength) {
|
|
137
|
-
bufferRemaining = data;
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
// Add it to our queue to be eventually pushed out through our generator function.
|
|
141
|
-
this.recordingBuffer.push({ data: data, header: header, length: dataLength, type: type });
|
|
142
|
-
this.emit("mp4box");
|
|
143
|
-
// Prepare to start a new box for the next buffer that we will be processing.
|
|
144
|
-
data = Buffer.alloc(0);
|
|
145
|
-
header = Buffer.alloc(0);
|
|
146
|
-
type = "";
|
|
147
|
-
// We've parsed an entire box, and there's no more data in this buffer to parse.
|
|
148
|
-
if (buffer.length === (offset + dataLength)) {
|
|
149
|
-
dataLength = 0;
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
// If there's anything left in the buffer, move us to the new box and let's keep iterating.
|
|
153
|
-
buffer = buffer.slice(offset + dataLength);
|
|
154
|
-
dataLength = 0;
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
// Make sure we cleanup our listeners when we're done.
|
|
158
|
-
this.process?.once("exit", () => {
|
|
159
|
-
this.process?.stdout?.off("data", dataListener);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
// Stop our FFmpeg process and cleanup after ourselves.
|
|
163
|
-
stopProcess() {
|
|
164
|
-
// Call our parent to get started.
|
|
165
|
-
super.stopProcess();
|
|
166
|
-
// Ensure that we clear out of our segment generator by guaranteeing an exit path.
|
|
167
|
-
this.isEnded = true;
|
|
168
|
-
this.emit("mp4box");
|
|
169
|
-
}
|
|
170
|
-
// Stop an FFmpeg process and cleanup.
|
|
171
|
-
stop(logErrors = this.isLoggingErrors) {
|
|
172
|
-
const savedLogErrors = this.isLoggingErrors;
|
|
173
|
-
// Flag whether we should log abnormal exits (e.g. being killed) or not.
|
|
174
|
-
this.isLoggingErrors = logErrors;
|
|
175
|
-
// Call our parent to finish the job.
|
|
176
|
-
super.stop();
|
|
177
|
-
// Restore our previous logging state.
|
|
178
|
-
this.isLoggingErrors = savedLogErrors;
|
|
179
|
-
}
|
|
180
|
-
// Log errors.
|
|
181
|
-
logFfmpegError(exitCode, signal) {
|
|
182
|
-
// If we're ignoring errors, we're done.
|
|
183
|
-
if (!this.isLoggingErrors) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
// Known HKSV-related errors due to occasional inconsistencies that are occasionally produced by the Protect livestream API.
|
|
187
|
-
const ffmpegKnownHksvError = new RegExp([
|
|
188
|
-
"(Cannot determine format of input stream 0:0 after EOF)",
|
|
189
|
-
"(Could not write header \\(incorrect codec parameters \\?\\): Broken pipe)",
|
|
190
|
-
"(Could not write header for output file #0)",
|
|
191
|
-
"(Error closing file: Broken pipe)",
|
|
192
|
-
"(Error splitting the input into NAL units\\.)",
|
|
193
|
-
"(Invalid data found when processing input)",
|
|
194
|
-
"(moov atom not found)"
|
|
195
|
-
].join("|"));
|
|
196
|
-
// See if we know about this error.
|
|
197
|
-
if (this.stderrLog.some(x => ffmpegKnownHksvError.test(x))) {
|
|
198
|
-
this.log.error("FFmpeg ended unexpectedly due to issues processing the media stream provided by the UniFi Protect livestream API. " +
|
|
199
|
-
"This error can be safely ignored - it will occur occasionally.");
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
// Otherwise, revert to our default logging in our parent.
|
|
203
|
-
super.logFfmpegError(exitCode, signal);
|
|
204
|
-
}
|
|
205
|
-
// Generate complete segments from an FFmpeg output stream that HomeKit Secure Video can process.
|
|
206
|
-
async *segmentGenerator() {
|
|
207
|
-
let segment = [];
|
|
208
|
-
// Loop forever, generating either FTYP/MOOV box pairs or MOOF/MDAT box pairs for HomeKit Secure Video.
|
|
209
|
-
for (;;) {
|
|
210
|
-
// FFmpeg has finished it's output - we're done.
|
|
211
|
-
if (this.isEnded) {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
// If the buffer is empty, wait for our FFmpeg process to produce more boxes.
|
|
215
|
-
if (!this.recordingBuffer.length) {
|
|
216
|
-
// Segments are output by FFmpeg according to our specified IDR interval. If we don't see a segment within the timeframe we need for HKSV's timing requirements,
|
|
217
|
-
// we flag it accordingly and return null back to the generator that's calling us.
|
|
218
|
-
// eslint-disable-next-line no-await-in-loop
|
|
219
|
-
await runWithTimeout(once(this, "mp4box"), PROTECT_HKSV_TIMEOUT);
|
|
220
|
-
}
|
|
221
|
-
// Grab the next fMP4 box from our buffer.
|
|
222
|
-
const box = this.recordingBuffer.shift();
|
|
223
|
-
// FFmpeg hasn't produced any output. Given the time-sensitive nature of HKSV that constrains us to no more than 5 seconds to provide the next segment, we're done.
|
|
224
|
-
if (!box) {
|
|
225
|
-
this.isTimedOut = true;
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
// Queue up this fMP4 box to send back to HomeKit.
|
|
229
|
-
segment.push(box.header, box.data);
|
|
230
|
-
// What we want to send are two types of complete segments, made up of multiple MP4 boxes:
|
|
231
|
-
//
|
|
232
|
-
// - a complete MOOV box, usually with an accompanying FTYP box, that's sent at the very beginning of any valid fMP4 stream. HomeKit Secure Video looks for this
|
|
233
|
-
// before anything else.
|
|
234
|
-
//
|
|
235
|
-
// - a complete MOOF/MDAT pair. MOOF describes the sample locations and their sizes and MDAT contains the actual audio and video data related to that segment. Think
|
|
236
|
-
// of MOOF as the audio/video data "header", and MDAT as the "payload".
|
|
237
|
-
//
|
|
238
|
-
// Once we see these, we combine all the segments in our queue to send back to HomeKit.
|
|
239
|
-
if ((box.type === "moov") || (box.type === "mdat")) {
|
|
240
|
-
yield Buffer.concat(segment);
|
|
241
|
-
segment = [];
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
//# sourceMappingURL=protect-ffmpeg-record.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"protect-ffmpeg-record.js","sourceRoot":"","sources":["../../src/ffmpeg/protect-ffmpeg-record.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ChildProcessWithoutNullStreams } from "child_process";
|
|
2
|
-
import { FfmpegProcess } from "./protect-ffmpeg.js";
|
|
3
|
-
import { Nullable } from "homebridge-plugin-utils";
|
|
4
|
-
import { ProtectStreamingDelegate } from "../protect-stream.js";
|
|
5
|
-
import { StreamRequestCallback } from "homebridge";
|
|
6
|
-
export declare class FfmpegStreamingProcess extends FfmpegProcess {
|
|
7
|
-
private delegate;
|
|
8
|
-
private sessionId;
|
|
9
|
-
private streamTimeout?;
|
|
10
|
-
constructor(delegate: ProtectStreamingDelegate, sessionId: string, commandLineArgs: string[], returnPort?: {
|
|
11
|
-
addressVersion: string;
|
|
12
|
-
port: number;
|
|
13
|
-
}, callback?: StreamRequestCallback);
|
|
14
|
-
private createSocket;
|
|
15
|
-
get ffmpegProcess(): Nullable<ChildProcessWithoutNullStreams>;
|
|
16
|
-
protected logFfmpegError(exitCode: number, signal: NodeJS.Signals): void;
|
|
17
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { FfmpegProcess } from "./protect-ffmpeg.js";
|
|
2
|
-
import { createSocket } from "node:dgram";
|
|
3
|
-
// FFmpeg streaming process management.
|
|
4
|
-
export class FfmpegStreamingProcess extends FfmpegProcess {
|
|
5
|
-
delegate;
|
|
6
|
-
sessionId;
|
|
7
|
-
streamTimeout;
|
|
8
|
-
// Create a new FFmpeg process instance.
|
|
9
|
-
constructor(delegate, sessionId, commandLineArgs, returnPort, callback) {
|
|
10
|
-
// Initialize our parent.
|
|
11
|
-
super(delegate.protectCamera);
|
|
12
|
-
this.delegate = delegate;
|
|
13
|
-
this.sessionId = sessionId;
|
|
14
|
-
// Create the return port for FFmpeg, if requested to do so. The only time we don't do this is when we're standing up
|
|
15
|
-
// a two-way audio stream - in that case, the audio work is done through RtpSplitter and not here.
|
|
16
|
-
if (returnPort) {
|
|
17
|
-
this.createSocket(returnPort);
|
|
18
|
-
}
|
|
19
|
-
// Start it up, with appropriate error handling.
|
|
20
|
-
this.start(commandLineArgs, callback, (errorMessage) => {
|
|
21
|
-
// Stop the stream.
|
|
22
|
-
this.delegate.stopStream(this.sessionId);
|
|
23
|
-
// Let homebridge know what happened and stop the stream if we've already started.
|
|
24
|
-
if (!this.isStarted && this.callback) {
|
|
25
|
-
this.callback(new Error(errorMessage));
|
|
26
|
-
this.callback = null;
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
// Tell Homebridge to forcibly stop the streaming session.
|
|
30
|
-
this.delegate.controller.forceStopStreamingSession(this.sessionId);
|
|
31
|
-
this.delegate.stopStream(this.sessionId);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
// Create the port for FFmpeg to send data through.
|
|
35
|
-
createSocket(portInfo) {
|
|
36
|
-
let errorListener;
|
|
37
|
-
let messageListener;
|
|
38
|
-
const socket = createSocket(portInfo.addressVersion === "ipv6" ? "udp6" : "udp4");
|
|
39
|
-
// Cleanup after ourselves when the socket closes.
|
|
40
|
-
socket.once("close", () => {
|
|
41
|
-
if (this.streamTimeout) {
|
|
42
|
-
clearTimeout(this.streamTimeout);
|
|
43
|
-
}
|
|
44
|
-
socket.off("error", errorListener);
|
|
45
|
-
socket.off("message", messageListener);
|
|
46
|
-
});
|
|
47
|
-
// Handle potential network errors.
|
|
48
|
-
socket.on("error", errorListener = (error) => {
|
|
49
|
-
this.log.error("Socket error: %s.", error.name);
|
|
50
|
-
void this.delegate.stopStream(this.sessionId);
|
|
51
|
-
});
|
|
52
|
-
// Manage our video streams in case we haven't received a stop request, but we're in fact dead zombies.
|
|
53
|
-
socket.on("message", messageListener = () => {
|
|
54
|
-
// Clear our last canary.
|
|
55
|
-
if (this.streamTimeout) {
|
|
56
|
-
clearTimeout(this.streamTimeout);
|
|
57
|
-
}
|
|
58
|
-
// Set our new canary.
|
|
59
|
-
this.streamTimeout = setTimeout(() => {
|
|
60
|
-
this.log.debug("Video stream appears to be inactive for 5 seconds. Stopping stream.", this.protectCamera.name);
|
|
61
|
-
this.delegate.controller.forceStopStreamingSession(this.sessionId);
|
|
62
|
-
void this.delegate.stopStream(this.sessionId);
|
|
63
|
-
}, 5000);
|
|
64
|
-
});
|
|
65
|
-
// Bind to the port we're opening.
|
|
66
|
-
socket.bind(portInfo.port, (portInfo.addressVersion === "ipv6") ? "::1" : "127.0.0.1");
|
|
67
|
-
}
|
|
68
|
-
// Return the actual FFmpeg process.
|
|
69
|
-
get ffmpegProcess() {
|
|
70
|
-
return this.process;
|
|
71
|
-
}
|
|
72
|
-
// Log errors.
|
|
73
|
-
logFfmpegError(exitCode, signal) {
|
|
74
|
-
// We want to process known streaming-related errors due to the performance and latency tweaks we've made to the FFmpeg command line. In some cases we inform the
|
|
75
|
-
// user and take no action, in others, we tune our own internal parameters.
|
|
76
|
-
// We're using API-based livestreaming. Be attentive to the unique errors they may present.
|
|
77
|
-
if (this.delegate.protectCamera.hints.apiStreaming && this.delegate.hksv?.isRecording) {
|
|
78
|
-
// Test for known errors due to occasional inconsistencies in the Protect livestream API.
|
|
79
|
-
const timeshiftLivestreamRegex = new RegExp([
|
|
80
|
-
"(Cannot determine format of input stream 0:0 after EOF)",
|
|
81
|
-
"(Finishing stream without any data written to it)",
|
|
82
|
-
"(could not find corresponding trex)",
|
|
83
|
-
"(moov atom not found)"
|
|
84
|
-
].join("|"));
|
|
85
|
-
if (this.stderrLog.some(logEntry => timeshiftLivestreamRegex.test(logEntry))) {
|
|
86
|
-
this.log.error("FFmpeg ended unexpectedly due to issues processing the media stream provided by the UniFi Protect livestream API. " +
|
|
87
|
-
"This error can be safely ignored - it will occur occasionally.");
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Test for probesize errors.
|
|
92
|
-
const probesizeRegex = new RegExp("not enough frames to estimate rate; consider increasing probesize");
|
|
93
|
-
if (this.stderrLog.some(logEntry => probesizeRegex.test(logEntry))) {
|
|
94
|
-
// Let the streaming delegate know to adjust it's parameters for the next run and inform the user.
|
|
95
|
-
this.delegate.adjustProbeSize();
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
// Otherwise, revert to our default logging in our parent.
|
|
99
|
-
super.logFfmpegError(exitCode, signal);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
//# sourceMappingURL=protect-ffmpeg-stream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"protect-ffmpeg-stream.js","sourceRoot":"","sources":["../../src/ffmpeg/protect-ffmpeg-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { ChildProcessWithoutNullStreams } from "node:child_process";
|
|
2
|
-
import { HomebridgePluginLogging, Nullable } from "homebridge-plugin-utils";
|
|
3
|
-
import { Readable, Writable } from "node:stream";
|
|
4
|
-
import { EventEmitter } from "node:events";
|
|
5
|
-
import { ProtectCamera } from "../devices/index.js";
|
|
6
|
-
import { ProtectNvr } from "../protect-nvr.js";
|
|
7
|
-
import { StreamRequestCallback } from "homebridge";
|
|
8
|
-
export declare class FfmpegProcess extends EventEmitter {
|
|
9
|
-
protected callback: Nullable<StreamRequestCallback>;
|
|
10
|
-
protected commandLineArgs: string[];
|
|
11
|
-
private ffmpegTimeout?;
|
|
12
|
-
hasError: boolean;
|
|
13
|
-
isEnded: boolean;
|
|
14
|
-
private isLogging;
|
|
15
|
-
private isPrepared;
|
|
16
|
-
isStarted: boolean;
|
|
17
|
-
protected isVerbose: boolean;
|
|
18
|
-
protected readonly log: HomebridgePluginLogging;
|
|
19
|
-
protected readonly nvr: ProtectNvr;
|
|
20
|
-
private readonly platform;
|
|
21
|
-
protected process: Nullable<ChildProcessWithoutNullStreams>;
|
|
22
|
-
protected protectCamera: ProtectCamera;
|
|
23
|
-
private stderrBuffer;
|
|
24
|
-
protected stderrLog: string[];
|
|
25
|
-
constructor(protectCamera: ProtectCamera, commandLineArgs?: string[], callback?: StreamRequestCallback);
|
|
26
|
-
protected prepareProcess(commandLineArgs?: string[], callback?: StreamRequestCallback): void;
|
|
27
|
-
protected start(commandLineArgs?: string[], callback?: StreamRequestCallback, errorHandler?: (errorMessage: string) => Promise<void> | void): void;
|
|
28
|
-
protected configureProcess(errorHandler?: (errorMessage: string) => Promise<void> | void): void;
|
|
29
|
-
protected stopProcess(): void;
|
|
30
|
-
stop(): void;
|
|
31
|
-
protected logFfmpegError(exitCode: number, signal: NodeJS.Signals): void;
|
|
32
|
-
get stdin(): Nullable<Writable>;
|
|
33
|
-
get stdout(): Nullable<Readable>;
|
|
34
|
-
get stderr(): Nullable<Readable>;
|
|
35
|
-
}
|