homebridge-eufy-security 2.2.4 → 2.3.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/CHANGELOG.md +39 -11
- package/README.md +26 -25
- package/dist/accessories/CameraAccessory.d.ts +55 -21
- package/dist/accessories/CameraAccessory.d.ts.map +1 -1
- package/dist/accessories/CameraAccessory.js +460 -214
- package/dist/accessories/CameraAccessory.js.map +1 -1
- package/dist/accessories/Device.d.ts +3 -3
- package/dist/accessories/Device.d.ts.map +1 -1
- package/dist/accessories/Device.js +15 -0
- package/dist/accessories/Device.js.map +1 -1
- package/dist/accessories/DoorbellCameraAccessory.d.ts +4 -1
- package/dist/accessories/DoorbellCameraAccessory.d.ts.map +1 -1
- package/dist/accessories/DoorbellCameraAccessory.js +65 -4
- package/dist/accessories/DoorbellCameraAccessory.js.map +1 -1
- package/dist/accessories/SmartLockAccessory.d.ts +2 -2
- package/dist/accessories/StationAccessory.d.ts +4 -0
- package/dist/accessories/StationAccessory.d.ts.map +1 -1
- package/dist/accessories/StationAccessory.js +64 -7
- package/dist/accessories/StationAccessory.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/controller/LocalLivestreamManager.d.ts +3 -8
- package/dist/controller/LocalLivestreamManager.d.ts.map +1 -1
- package/dist/controller/LocalLivestreamManager.js +4 -47
- package/dist/controller/LocalLivestreamManager.js.map +1 -1
- package/dist/controller/SnapshotManager.d.ts +1 -1
- package/dist/controller/SnapshotManager.d.ts.map +1 -1
- package/dist/controller/SnapshotManager.js +23 -1
- package/dist/controller/SnapshotManager.js.map +1 -1
- package/dist/controller/recordingDelegate.d.ts +29 -0
- package/dist/controller/recordingDelegate.d.ts.map +1 -0
- package/dist/controller/recordingDelegate.js +186 -0
- package/dist/controller/recordingDelegate.js.map +1 -0
- package/dist/controller/streamingDelegate.d.ts +6 -6
- package/dist/controller/streamingDelegate.d.ts.map +1 -1
- package/dist/controller/streamingDelegate.js +21 -60
- package/dist/controller/streamingDelegate.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/platform.d.ts +6 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +112 -66
- package/dist/platform.js.map +1 -1
- package/dist/utils/EufyClientInteractor.d.ts +36 -0
- package/dist/utils/EufyClientInteractor.d.ts.map +1 -0
- package/dist/utils/EufyClientInteractor.js +357 -0
- package/dist/utils/EufyClientInteractor.js.map +1 -0
- package/dist/utils/Talkback.d.ts +0 -1
- package/dist/utils/Talkback.d.ts.map +1 -1
- package/dist/utils/configTypes.d.ts +15 -5
- package/dist/utils/configTypes.d.ts.map +1 -1
- package/dist/utils/experimental.d.ts +4 -0
- package/dist/utils/experimental.d.ts.map +1 -0
- package/dist/utils/experimental.js +49 -0
- package/dist/utils/experimental.js.map +1 -0
- package/dist/utils/ffmpeg.d.ts +30 -4
- package/dist/utils/ffmpeg.d.ts.map +1 -1
- package/dist/utils/ffmpeg.js +322 -30
- package/dist/utils/ffmpeg.js.map +1 -1
- package/dist/utils/interfaces.d.ts +13 -0
- package/dist/utils/interfaces.d.ts.map +1 -0
- package/dist/utils/interfaces.js +12 -0
- package/dist/utils/interfaces.js.map +1 -0
- package/homebridge-ui/configui/app/accessory.d.ts +1 -1
- package/homebridge-ui/configui/app/accessory.d.ts.map +1 -1
- package/homebridge-ui/configui/app/util/types.d.ts +2 -2
- package/homebridge-ui/configui/app/util/types.d.ts.map +1 -1
- package/homebridge-ui/configui/app/util/types.js +1 -1
- package/homebridge-ui/configui/app/util/types.js.map +1 -1
- package/homebridge-ui/plugin/utils/EufyClientInteractor.d.ts +36 -0
- package/homebridge-ui/plugin/utils/EufyClientInteractor.d.ts.map +1 -0
- package/homebridge-ui/plugin/utils/EufyClientInteractor.js +357 -0
- package/homebridge-ui/plugin/utils/EufyClientInteractor.js.map +1 -0
- package/homebridge-ui/plugin/utils/experimental.d.ts +4 -0
- package/homebridge-ui/plugin/utils/experimental.d.ts.map +1 -0
- package/homebridge-ui/plugin/utils/experimental.js +49 -0
- package/homebridge-ui/plugin/utils/experimental.js.map +1 -0
- package/homebridge-ui/plugin/utils/interfaces.d.ts +13 -0
- package/homebridge-ui/plugin/utils/interfaces.d.ts.map +1 -0
- package/homebridge-ui/plugin/utils/interfaces.js +12 -0
- package/homebridge-ui/plugin/utils/interfaces.js.map +1 -0
- package/homebridge-ui/plugin/utils/logger.d.ts +12 -0
- package/homebridge-ui/plugin/utils/logger.d.ts.map +1 -0
- package/homebridge-ui/plugin/utils/logger.js +36 -0
- package/homebridge-ui/plugin/utils/logger.js.map +1 -0
- package/homebridge-ui/public/3rdpartylicenses.txt +191 -6
- package/homebridge-ui/public/index.html +2 -2
- package/homebridge-ui/public/main.22a0c49e2138888f.js +1 -0
- package/homebridge-ui/public/polyfills.6050693665c0e882.js +1 -0
- package/homebridge-ui/public/styles.e02689e7df4304da.css +6 -0
- package/homebridge-ui/server.js +17 -1
- package/homebridge-ui/server.js.map +1 -1
- package/package.json +48 -46
- package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s100_large.jpg +0 -0
- package/homebridge-ui/public/main.0d25748cc9303f6b.js +0 -1
- package/homebridge-ui/public/polyfills.cdb21ff95fdea645.js +0 -1
- package/homebridge-ui/public/styles.021488511c20c432.css +0 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experimental.js","sourceRoot":"","sources":["../../src/plugin/utils/experimental.ts"],"names":[],"mappings":";;;AAAA,+DAS8B;AAEvB,MAAM,0BAA0B,GAAG,GAAG,EAAE;IAC7C,6BAA6B,EAAE,CAAC;AAClC,CAAC,CAAC;AAFW,QAAA,0BAA0B,8BAErC;AAEF,mCAAY,CAAC,0BAA0B,CAAC,GAAG,0BAA0B,CAAC;AAEtE,MAAM,8BAA8B,GAA4B;IAC9D,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,mCAAY,CAAC,0BAA0B,CAAC;IAC9C,KAAK,EAAE,2BAA2B;IAClC,QAAQ,EAAE,IAAI;IACd,SAAS,EAAE,KAAK;IAChB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF,MAAM,6BAA6B,GAAG,GAAG,EAAE;IACzC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,iCAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC,CAAC;AAC3E,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAAC,UAA+B,EAAE,EAAE;IACpE,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,IAAI,uCAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,uCAAgB,CAAC,UAAU,CAAC,CAAC,mCAAY,CAAC,gBAAgB,CAAC,EAAE;QAChG,uCAAgB,CAAC,UAAU,CAAC,GAAG;YAC7B,GAAG,uCAAgB,CAAC,UAAU,CAAC;YAC/B,CAAC,mCAAY,CAAC,gBAAgB,CAAC,EAAE,+CAAwB;SAC1D,CAAC;QACF,OAAO,GAAG,IAAI,CAAC;KAChB;IAED,IAAI,uCAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,uCAAgB,CAAC,UAAU,CAAC,CAAC,mCAAY,CAAC,mBAAmB,CAAC,EAAE;QACnG,uCAAgB,CAAC,UAAU,CAAC,GAAG;YAC7B,GAAG,uCAAgB,CAAC,UAAU,CAAC;YAC/B,CAAC,mCAAY,CAAC,mBAAmB,CAAC,EAAE,kDAA2B;SAChE,CAAC;QACF,OAAO,GAAG,IAAI,CAAC;KAChB;IAED,IAAI,OAAO,IAAI,uCAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,uCAAgB,CAAC,UAAU,CAAC,CAAC,mCAAY,CAAC,0BAA0B,CAAC,CAAC,EAAE;QACtH,uCAAgB,CAAC,UAAU,CAAC,GAAG;YAC7B,GAAG,uCAAgB,CAAC,UAAU,CAAC;YAC/B,CAAC,mCAAY,CAAC,0BAA0B,CAAC,CAAC,EAAE,8BAA8B;SAC3E,CAAC;KACH;AACH,CAAC,CAAC;AAEK,MAAM,iBAAiB,GAAG,CAAC,OAAgB,EAAE,MAAc,EAAE,KAAc,EAAE,EAAE;IACpF,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC,CAAC;AAFW,QAAA,iBAAiB,qBAE5B"}
|
package/dist/utils/ffmpeg.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { ChildProcessWithoutNullStreams } from 'child_process';
|
|
3
|
+
import net from 'net';
|
|
4
4
|
import { Readable, Writable } from 'stream';
|
|
5
5
|
import { Logger } from './logger';
|
|
6
6
|
import EventEmitter from 'events';
|
|
7
|
-
import { CameraConfig } from './configTypes';
|
|
8
|
-
import { ReconfigureStreamRequest, SnapshotRequest, StartStreamRequest } from 'homebridge';
|
|
7
|
+
import { CameraConfig, VideoConfig } from './configTypes';
|
|
8
|
+
import { CameraRecordingConfiguration, ReconfigureStreamRequest, SnapshotRequest, StartStreamRequest } from 'homebridge';
|
|
9
9
|
import { SessionInfo } from '../controller/streamingDelegate';
|
|
10
10
|
export declare class FFmpegParameters {
|
|
11
11
|
progressPort: number;
|
|
12
12
|
debug: boolean;
|
|
13
|
+
processor?: string;
|
|
13
14
|
private hideBanner;
|
|
14
15
|
private useWallclockAsTimestamp;
|
|
15
16
|
private inputSoure;
|
|
@@ -40,15 +41,22 @@ export declare class FFmpegParameters {
|
|
|
40
41
|
private height?;
|
|
41
42
|
private bufsize?;
|
|
42
43
|
private maxrate?;
|
|
44
|
+
private crop;
|
|
43
45
|
private sampleRate?;
|
|
44
46
|
private channels?;
|
|
45
47
|
private flagsGlobalHeader;
|
|
46
48
|
private numberFrames?;
|
|
47
49
|
private delaySnapshot;
|
|
50
|
+
private movflags?;
|
|
51
|
+
private maxMuxingQueueSize?;
|
|
52
|
+
private iFrameInterval?;
|
|
53
|
+
private processAudio;
|
|
48
54
|
private constructor();
|
|
49
55
|
static forAudio(debug?: boolean): Promise<FFmpegParameters>;
|
|
50
56
|
static forVideo(debug?: boolean): Promise<FFmpegParameters>;
|
|
51
57
|
static forSnapshot(debug?: boolean): Promise<FFmpegParameters>;
|
|
58
|
+
static forVideoRecording(debug?: boolean): Promise<FFmpegParameters>;
|
|
59
|
+
static forAudioRecording(debug?: boolean): Promise<FFmpegParameters>;
|
|
52
60
|
setResolution(width: number, height: number): void;
|
|
53
61
|
usesStdInAsInput(): boolean;
|
|
54
62
|
setInputSource(value: string): void;
|
|
@@ -56,15 +64,21 @@ export declare class FFmpegParameters {
|
|
|
56
64
|
setDelayedSnapshot(): void;
|
|
57
65
|
setup(cameraConfig: CameraConfig, request: StartStreamRequest | ReconfigureStreamRequest | SnapshotRequest | undefined): void;
|
|
58
66
|
setRTPTarget(sessionInfo: SessionInfo, request: StartStreamRequest): void;
|
|
67
|
+
setOutput(output: string): void;
|
|
68
|
+
setupForRecording(videoConfig: VideoConfig, configuration: CameraRecordingConfiguration): void;
|
|
59
69
|
setTalkbackInput(sessionInfo: SessionInfo): Promise<void>;
|
|
70
|
+
setTalkbackChannels(channels: number): void;
|
|
60
71
|
private buildGenericParameters;
|
|
61
72
|
private buildInputParamters;
|
|
62
73
|
private buildEncodingParameters;
|
|
63
74
|
private buildOutputParameters;
|
|
64
75
|
private buildParameters;
|
|
65
76
|
getProcessArguments(): string[];
|
|
77
|
+
static getRecordingArguments(parameters: FFmpegParameters[]): string[];
|
|
66
78
|
static getCombinedArguments(parameters: FFmpegParameters[]): string[];
|
|
67
79
|
getStreamStartText(): string;
|
|
80
|
+
hasCustomFfmpeg(): boolean;
|
|
81
|
+
getCustomFfmpeg(): string;
|
|
68
82
|
}
|
|
69
83
|
export declare class FFmpeg extends EventEmitter {
|
|
70
84
|
private process?;
|
|
@@ -80,6 +94,18 @@ export declare class FFmpeg extends EventEmitter {
|
|
|
80
94
|
constructor(name: string, parameters: FFmpegParameters | FFmpegParameters[], log: Logger);
|
|
81
95
|
start(): void;
|
|
82
96
|
getResult(input?: Buffer): Promise<Buffer>;
|
|
97
|
+
startFragmentedMP4Session(): Promise<{
|
|
98
|
+
socket: net.Socket;
|
|
99
|
+
process?: ChildProcessWithoutNullStreams;
|
|
100
|
+
generator: AsyncGenerator<{
|
|
101
|
+
header: Buffer;
|
|
102
|
+
length: number;
|
|
103
|
+
type: string;
|
|
104
|
+
data: Buffer;
|
|
105
|
+
}>;
|
|
106
|
+
}>;
|
|
107
|
+
private parseFragmentedMP4;
|
|
108
|
+
private readLength;
|
|
83
109
|
stop(): void;
|
|
84
110
|
private onProgressStarted;
|
|
85
111
|
private onProcessError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../../src/plugin/utils/ffmpeg.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../../src/plugin/utils/ffmpeg.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/ffmpeg.js
CHANGED
|
@@ -56,14 +56,15 @@ class FFmpegProgress extends events_1.default {
|
|
|
56
56
|
}
|
|
57
57
|
class FFmpegParameters {
|
|
58
58
|
constructor(port, isVideo, isAudio, isSnapshot, debug = false) {
|
|
59
|
-
// default parameters
|
|
60
59
|
this.hideBanner = true;
|
|
61
60
|
this.useWallclockAsTimestamp = true;
|
|
62
61
|
this.inputSoure = '-i pipe:';
|
|
63
62
|
this.output = 'pipe:1';
|
|
64
63
|
this.codec = 'copy';
|
|
64
|
+
this.crop = false;
|
|
65
65
|
this.flagsGlobalHeader = false;
|
|
66
66
|
this.delaySnapshot = false;
|
|
67
|
+
this.processAudio = true;
|
|
67
68
|
this.progressPort = port;
|
|
68
69
|
this.isVideo = isVideo;
|
|
69
70
|
this.isAudio = isAudio;
|
|
@@ -101,6 +102,25 @@ class FFmpegParameters {
|
|
|
101
102
|
ffmpeg.format = 'image2';
|
|
102
103
|
return ffmpeg;
|
|
103
104
|
}
|
|
105
|
+
static async forVideoRecording(debug = false) {
|
|
106
|
+
const port = await (0, pick_port_1.default)({
|
|
107
|
+
type: 'tcp',
|
|
108
|
+
ip: '0.0.0.0',
|
|
109
|
+
reserveTimeout: 15,
|
|
110
|
+
});
|
|
111
|
+
const ffmpeg = new FFmpegParameters(port, true, false, false, debug);
|
|
112
|
+
ffmpeg.useWallclockAsTimestamp = true;
|
|
113
|
+
return ffmpeg;
|
|
114
|
+
}
|
|
115
|
+
static async forAudioRecording(debug = false) {
|
|
116
|
+
const port = await (0, pick_port_1.default)({
|
|
117
|
+
type: 'tcp',
|
|
118
|
+
ip: '0.0.0.0',
|
|
119
|
+
reserveTimeout: 15,
|
|
120
|
+
});
|
|
121
|
+
const ffmpeg = new FFmpegParameters(port, false, true, false, debug);
|
|
122
|
+
return ffmpeg;
|
|
123
|
+
}
|
|
104
124
|
setResolution(width, height) {
|
|
105
125
|
this.width = width;
|
|
106
126
|
this.height = height;
|
|
@@ -109,7 +129,6 @@ class FFmpegParameters {
|
|
|
109
129
|
return this.inputSoure === '-i pipe:';
|
|
110
130
|
}
|
|
111
131
|
setInputSource(value) {
|
|
112
|
-
// TODO: check for errors
|
|
113
132
|
this.inputSoure = `-i ${value}`;
|
|
114
133
|
}
|
|
115
134
|
async setInputStream(input) {
|
|
@@ -144,6 +163,9 @@ class FFmpegParameters {
|
|
|
144
163
|
setup(cameraConfig, request) {
|
|
145
164
|
var _a;
|
|
146
165
|
const videoConfig = (_a = cameraConfig.videoConfig) !== null && _a !== void 0 ? _a : (cameraConfig.videoConfig = {});
|
|
166
|
+
if (videoConfig.videoProcessor && videoConfig.videoProcessor !== '') {
|
|
167
|
+
this.processor = videoConfig.videoProcessor;
|
|
168
|
+
}
|
|
147
169
|
if (videoConfig.readRate) {
|
|
148
170
|
this.readrate = videoConfig.readRate;
|
|
149
171
|
}
|
|
@@ -171,7 +193,7 @@ class FFmpegParameters {
|
|
|
171
193
|
this.bufsize = bitrate * 2;
|
|
172
194
|
this.maxrate = bitrate;
|
|
173
195
|
let encoderOptions = codec === 'libx264' ? '-preset ultrafast -tune zerolatency' : '';
|
|
174
|
-
if (videoConfig.encoderOptions
|
|
196
|
+
if (videoConfig.encoderOptions) {
|
|
175
197
|
encoderOptions = videoConfig.encoderOptions;
|
|
176
198
|
}
|
|
177
199
|
this.codecOptions = encoderOptions;
|
|
@@ -190,16 +212,32 @@ class FFmpegParameters {
|
|
|
190
212
|
if (videoConfig.videoFilter && videoConfig.videoFilter !== '') {
|
|
191
213
|
this.filters = videoConfig.videoFilter;
|
|
192
214
|
}
|
|
215
|
+
if (videoConfig.crop) {
|
|
216
|
+
this.crop = videoConfig.crop;
|
|
217
|
+
}
|
|
193
218
|
}
|
|
194
219
|
}
|
|
195
220
|
if (this.isAudio) {
|
|
196
221
|
const req = request;
|
|
197
|
-
let codec =
|
|
198
|
-
let codecOptions =
|
|
222
|
+
let codec = 'libfdk_aac';
|
|
223
|
+
let codecOptions = '-profile:a aac_eld';
|
|
224
|
+
switch (req.audio.codec) {
|
|
225
|
+
case "OPUS" /* OPUS */:
|
|
226
|
+
codec = 'libopus';
|
|
227
|
+
codecOptions = '-application lowdelay';
|
|
228
|
+
break;
|
|
229
|
+
default:
|
|
230
|
+
codec = 'libfdk_aac';
|
|
231
|
+
codecOptions = '-profile:a aac_eld';
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
199
234
|
if (videoConfig.acodec && videoConfig.acodec !== '') {
|
|
200
235
|
codec = videoConfig.acodec;
|
|
201
236
|
codecOptions = '';
|
|
202
237
|
}
|
|
238
|
+
if (videoConfig.acodecOptions !== undefined) {
|
|
239
|
+
codecOptions = videoConfig.acodecOptions;
|
|
240
|
+
}
|
|
203
241
|
if (this.flagsGlobalHeader) {
|
|
204
242
|
if (codecOptions !== '') {
|
|
205
243
|
codecOptions += ' ';
|
|
@@ -208,15 +246,10 @@ class FFmpegParameters {
|
|
|
208
246
|
}
|
|
209
247
|
this.codec = codec;
|
|
210
248
|
this.codecOptions = codecOptions;
|
|
211
|
-
let samplerate = req.audio.sample_rate;
|
|
212
|
-
if (videoConfig.audioSampleRate &&
|
|
213
|
-
(videoConfig.audioSampleRate === 8 || videoConfig.audioSampleRate === 16 || videoConfig.audioSampleRate === 24)) {
|
|
214
|
-
samplerate = videoConfig.audioSampleRate;
|
|
215
|
-
}
|
|
216
249
|
if (this.codec !== ' copy') {
|
|
217
|
-
this.sampleRate =
|
|
250
|
+
this.sampleRate = req.audio.sample_rate;
|
|
218
251
|
this.channels = req.audio.channel;
|
|
219
|
-
this.bitrate = req.audio.max_bit_rate;
|
|
252
|
+
this.bitrate = videoConfig.audioBitrate ? videoConfig.audioBitrate : req.audio.max_bit_rate;
|
|
220
253
|
}
|
|
221
254
|
}
|
|
222
255
|
if (this.isSnapshot) {
|
|
@@ -234,6 +267,9 @@ class FFmpegParameters {
|
|
|
234
267
|
if (videoConfig.videoFilter && videoConfig.videoFilter !== '') {
|
|
235
268
|
this.filters = videoConfig.videoFilter;
|
|
236
269
|
}
|
|
270
|
+
if (videoConfig.crop) {
|
|
271
|
+
this.crop = videoConfig.crop;
|
|
272
|
+
}
|
|
237
273
|
}
|
|
238
274
|
}
|
|
239
275
|
setRTPTarget(sessionInfo, request) {
|
|
@@ -254,6 +290,92 @@ class FFmpegParameters {
|
|
|
254
290
|
this.output = `srtp://${sessionInfo.address}:${sessionInfo.audioPort}?rtcpport=${sessionInfo.audioPort}&pkt_size=188`;
|
|
255
291
|
}
|
|
256
292
|
}
|
|
293
|
+
setOutput(output) {
|
|
294
|
+
this.output = output;
|
|
295
|
+
}
|
|
296
|
+
setupForRecording(videoConfig, configuration) {
|
|
297
|
+
var _a, _b;
|
|
298
|
+
this.movflags = 'frag_keyframe+empty_moov+default_base_moof';
|
|
299
|
+
this.maxMuxingQueueSize = 1024;
|
|
300
|
+
if (videoConfig.videoProcessor && videoConfig.videoProcessor !== '') {
|
|
301
|
+
this.processor = videoConfig.videoProcessor;
|
|
302
|
+
}
|
|
303
|
+
if (this.isVideo) {
|
|
304
|
+
if (videoConfig.vcodec && videoConfig.vcodec !== '') {
|
|
305
|
+
this.codec = videoConfig.vcodec;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
this.codec = 'libx264';
|
|
309
|
+
}
|
|
310
|
+
if (this.codec === 'libx264') {
|
|
311
|
+
this.pixFormat = 'yuv420p';
|
|
312
|
+
const profile = configuration.videoCodec.parameters.profile === 2 /* HIGH */
|
|
313
|
+
? 'high'
|
|
314
|
+
: configuration.videoCodec.parameters.profile === 1 /* MAIN */
|
|
315
|
+
? 'main'
|
|
316
|
+
: 'baseline';
|
|
317
|
+
const level = configuration.videoCodec.parameters.level === 2 /* LEVEL4_0 */
|
|
318
|
+
? '4.0'
|
|
319
|
+
: configuration.videoCodec.parameters.level === 1 /* LEVEL3_2 */
|
|
320
|
+
? '3.2'
|
|
321
|
+
: '3.1';
|
|
322
|
+
this.codecOptions = `-profile:v ${profile} -level:v ${level}`;
|
|
323
|
+
}
|
|
324
|
+
if (this.codec !== 'copy') {
|
|
325
|
+
this.bitrate = (_a = videoConfig.maxBitrate) !== null && _a !== void 0 ? _a : configuration.videoCodec.parameters.bitRate;
|
|
326
|
+
this.width = configuration.videoCodec.resolution[0];
|
|
327
|
+
this.height = configuration.videoCodec.resolution[1];
|
|
328
|
+
this.fps = (_b = videoConfig.maxFPS) !== null && _b !== void 0 ? _b : configuration.videoCodec.resolution[2];
|
|
329
|
+
this.crop = (videoConfig.crop !== false); // only false if 'crop: false' was specifically set
|
|
330
|
+
}
|
|
331
|
+
this.iFrameInterval = configuration.videoCodec.parameters.iFrameInterval;
|
|
332
|
+
}
|
|
333
|
+
if (this.isAudio) {
|
|
334
|
+
if (videoConfig.audio === false) {
|
|
335
|
+
this.processAudio = false;
|
|
336
|
+
}
|
|
337
|
+
if (videoConfig.acodec && videoConfig.acodec !== '') {
|
|
338
|
+
this.codec = videoConfig.acodec;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
this.codec = 'libfdk_aac';
|
|
342
|
+
}
|
|
343
|
+
if (this.codec === 'libfdk_aac' || this.codec === 'aac') {
|
|
344
|
+
this.codecOptions = (configuration.audioCodec.type === 0 /* AAC_LC */)
|
|
345
|
+
? '-profile:a aac_low'
|
|
346
|
+
: '-profile:a aac_eld';
|
|
347
|
+
this.codecOptions += ' -flags +global_header';
|
|
348
|
+
}
|
|
349
|
+
if (this.codec !== 'copy') {
|
|
350
|
+
let samplerate;
|
|
351
|
+
switch (configuration.audioCodec.samplerate) {
|
|
352
|
+
case 0 /* KHZ_8 */:
|
|
353
|
+
samplerate = '8';
|
|
354
|
+
break;
|
|
355
|
+
case 1 /* KHZ_16 */:
|
|
356
|
+
samplerate = '16';
|
|
357
|
+
break;
|
|
358
|
+
case 2 /* KHZ_24 */:
|
|
359
|
+
samplerate = '24';
|
|
360
|
+
break;
|
|
361
|
+
case 3 /* KHZ_32 */:
|
|
362
|
+
samplerate = '32';
|
|
363
|
+
break;
|
|
364
|
+
case 4 /* KHZ_44_1 */:
|
|
365
|
+
samplerate = '44.1';
|
|
366
|
+
break;
|
|
367
|
+
case 5 /* KHZ_48 */:
|
|
368
|
+
samplerate = '48';
|
|
369
|
+
break;
|
|
370
|
+
default:
|
|
371
|
+
throw new Error(`Unsupported audio samplerate: ${configuration.audioCodec.samplerate}`);
|
|
372
|
+
}
|
|
373
|
+
this.sampleRate = samplerate;
|
|
374
|
+
this.bitrate = configuration.audioCodec.bitrate;
|
|
375
|
+
this.channels = configuration.audioCodec.audioChannels;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
257
379
|
async setTalkbackInput(sessionInfo) {
|
|
258
380
|
this.useWallclockAsTimestamp = false;
|
|
259
381
|
this.protocolWhitelist = 'pipe,udp,rtp,file,crypto,tcp';
|
|
@@ -303,6 +425,9 @@ class FFmpegParameters {
|
|
|
303
425
|
}, 30 * 1000);
|
|
304
426
|
this.setInputSource(`tcp://127.0.0.1:${port}`);
|
|
305
427
|
}
|
|
428
|
+
setTalkbackChannels(channels) {
|
|
429
|
+
this.channels = channels;
|
|
430
|
+
}
|
|
306
431
|
buildGenericParameters() {
|
|
307
432
|
const params = [];
|
|
308
433
|
params.push(this.hideBanner ? '-hide_banner' : '');
|
|
@@ -340,13 +465,21 @@ class FFmpegParameters {
|
|
|
340
465
|
filters.splice(noneFilter, 1);
|
|
341
466
|
}
|
|
342
467
|
if (noneFilter < 0 && this.width && this.height) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
':
|
|
348
|
-
|
|
349
|
-
|
|
468
|
+
if (this.crop) {
|
|
469
|
+
const resizeFilter = `scale=${this.width}:${this.height}:force_original_aspect_ratio=increase`;
|
|
470
|
+
filters.push(resizeFilter);
|
|
471
|
+
filters.push(`crop=${this.width}:${this.height}`);
|
|
472
|
+
filters.push(`scale='trunc(${this.width}/2)*2:trunc(${this.height}/2)*2'`); // Force to fit encoder restrictions
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
const resizeFilter = 'scale=' +
|
|
476
|
+
'\'min(' + this.width + ',iw)\'' +
|
|
477
|
+
':' +
|
|
478
|
+
'\'min(' + this.height + ',ih)\'' +
|
|
479
|
+
':force_original_aspect_ratio=decrease';
|
|
480
|
+
filters.push(resizeFilter);
|
|
481
|
+
filters.push('scale=\'trunc(iw/2)*2:trunc(ih/2)*2\''); // Force to fit encoder restrictions
|
|
482
|
+
}
|
|
350
483
|
}
|
|
351
484
|
if (filters.length > 0) {
|
|
352
485
|
params.push('-filter:v ' + filters.join(','));
|
|
@@ -355,7 +488,7 @@ class FFmpegParameters {
|
|
|
355
488
|
params.push(this.bufsize ? '-bufsize ' + this.bufsize + 'k' : '');
|
|
356
489
|
params.push(this.maxrate ? `-maxrate ${this.maxrate}k` : '');
|
|
357
490
|
}
|
|
358
|
-
if (this.isAudio) {
|
|
491
|
+
if (this.isAudio && this.processAudio) {
|
|
359
492
|
// audio parameters
|
|
360
493
|
params.push('-acodec ' + this.codec);
|
|
361
494
|
params.push(this.codecOptions ? this.codecOptions : '');
|
|
@@ -372,13 +505,21 @@ class FFmpegParameters {
|
|
|
372
505
|
filters.splice(noneFilter, 1);
|
|
373
506
|
}
|
|
374
507
|
if (noneFilter < 0 && this.width && this.height) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
':
|
|
380
|
-
|
|
381
|
-
|
|
508
|
+
if (this.crop) {
|
|
509
|
+
const resizeFilter = `scale=${this.width}:${this.height}:force_original_aspect_ratio=increase`;
|
|
510
|
+
filters.push(resizeFilter);
|
|
511
|
+
filters.push(`crop=${this.width}:${this.height}`);
|
|
512
|
+
filters.push(`scale='trunc(${this.width}/2)*2:trunc(${this.height}/2)*2'`); // Force to fit encoder restrictions
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
const resizeFilter = 'scale=' +
|
|
516
|
+
'\'min(' + this.width + ',iw)\'' +
|
|
517
|
+
':' +
|
|
518
|
+
'\'min(' + this.height + ',ih)\'' +
|
|
519
|
+
':force_original_aspect_ratio=decrease';
|
|
520
|
+
filters.push(resizeFilter);
|
|
521
|
+
filters.push('scale=\'trunc(iw/2)*2:trunc(ih/2)*2\''); // Force to fit encoder restrictions
|
|
522
|
+
}
|
|
382
523
|
}
|
|
383
524
|
if (filters.length > 0) {
|
|
384
525
|
params.push('-filter:v ' + filters.join(','));
|
|
@@ -410,6 +551,46 @@ class FFmpegParameters {
|
|
|
410
551
|
getProcessArguments() {
|
|
411
552
|
return this.buildParameters();
|
|
412
553
|
}
|
|
554
|
+
static getRecordingArguments(parameters) {
|
|
555
|
+
let params = [];
|
|
556
|
+
if (parameters.length === 0) {
|
|
557
|
+
return params;
|
|
558
|
+
}
|
|
559
|
+
params = parameters[0].buildGenericParameters();
|
|
560
|
+
// input
|
|
561
|
+
params.push(parameters[0].inputSoure);
|
|
562
|
+
if (parameters.length > 1 && parameters[0].inputSoure !== parameters[1].inputSoure) { // don't include extra audio source for rtsp
|
|
563
|
+
if (parameters[1].processAudio) {
|
|
564
|
+
params.push(parameters[1].inputSoure);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
params.push('-f lavfi -i anullsrc -shortest');
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (parameters.length === 1) {
|
|
571
|
+
params.push('-an');
|
|
572
|
+
}
|
|
573
|
+
params.push('-sn -dn');
|
|
574
|
+
// video encoding
|
|
575
|
+
params = params.concat(parameters[0].buildEncodingParameters());
|
|
576
|
+
params.push(parameters[0].iFrameInterval ? `-force_key_frames expr:gte(t,n_forced*${parameters[0].iFrameInterval / 1000})` : '');
|
|
577
|
+
// audio encoding
|
|
578
|
+
if (parameters.length > 1) {
|
|
579
|
+
if (parameters[1].processAudio) {
|
|
580
|
+
params.push('-bsf:a aac_adtstoasc');
|
|
581
|
+
}
|
|
582
|
+
params = params.concat(parameters[1].buildEncodingParameters());
|
|
583
|
+
}
|
|
584
|
+
// fragmented mp4 options
|
|
585
|
+
params.push(parameters[0].movflags ? `-movflags ${parameters[0].movflags}` : '');
|
|
586
|
+
params.push(parameters[0].maxMuxingQueueSize ? `-max_muxing_queue_size ${parameters[0].maxMuxingQueueSize}` : '');
|
|
587
|
+
// output
|
|
588
|
+
params.push('-f mp4');
|
|
589
|
+
params.push(parameters[0].output);
|
|
590
|
+
params.push(`-progress tcp://127.0.0.1:${parameters[0].progressPort}`);
|
|
591
|
+
params = params.filter(x => x !== '');
|
|
592
|
+
return params;
|
|
593
|
+
}
|
|
413
594
|
static getCombinedArguments(parameters) {
|
|
414
595
|
let params = [];
|
|
415
596
|
if (parameters.length === 0) {
|
|
@@ -437,6 +618,12 @@ class FFmpegParameters {
|
|
|
437
618
|
}
|
|
438
619
|
return 'Starting unknown stream';
|
|
439
620
|
}
|
|
621
|
+
hasCustomFfmpeg() {
|
|
622
|
+
return (this.processor !== undefined);
|
|
623
|
+
}
|
|
624
|
+
getCustomFfmpeg() {
|
|
625
|
+
return (this.hasCustomFfmpeg()) ? this.processor : '';
|
|
626
|
+
}
|
|
440
627
|
}
|
|
441
628
|
exports.FFmpegParameters = FFmpegParameters;
|
|
442
629
|
class FFmpeg extends events_1.default {
|
|
@@ -454,6 +641,9 @@ class FFmpeg extends events_1.default {
|
|
|
454
641
|
else {
|
|
455
642
|
this.parameters = [parameters];
|
|
456
643
|
}
|
|
644
|
+
if (this.parameters[0].hasCustomFfmpeg()) {
|
|
645
|
+
this.ffmpegExec = this.parameters[0].getCustomFfmpeg();
|
|
646
|
+
}
|
|
457
647
|
}
|
|
458
648
|
start() {
|
|
459
649
|
this.starttime = Date.now();
|
|
@@ -468,9 +658,15 @@ class FFmpeg extends events_1.default {
|
|
|
468
658
|
this.stdin = this.process.stdin;
|
|
469
659
|
this.stdout = this.process.stdout;
|
|
470
660
|
this.process.stderr.on('data', (chunk) => {
|
|
471
|
-
|
|
661
|
+
const isError = chunk.toString().indexOf('[panic]') !== -1 ||
|
|
662
|
+
chunk.toString().indexOf('[error]') !== -1 ||
|
|
663
|
+
chunk.toString().indexOf('[fatal]') !== -1;
|
|
664
|
+
if (this.parameters[0].debug && !isError) {
|
|
472
665
|
this.log.debug(this.name, 'ffmpeg log message:\n' + chunk.toString());
|
|
473
666
|
}
|
|
667
|
+
else if (isError) {
|
|
668
|
+
this.log.error(this.name, 'ffmpeg log message:\n' + chunk.toString());
|
|
669
|
+
}
|
|
474
670
|
});
|
|
475
671
|
this.process.on('error', this.onProcessError.bind(this));
|
|
476
672
|
this.process.on('exit', this.onProcessExit.bind(this));
|
|
@@ -484,9 +680,15 @@ class FFmpeg extends events_1.default {
|
|
|
484
680
|
return new Promise((resolve, reject) => {
|
|
485
681
|
this.process = (0, child_process_1.spawn)(this.ffmpegExec, processArgs.join(' ').split(/\s+/), { env: process.env });
|
|
486
682
|
this.process.stderr.on('data', (chunk) => {
|
|
487
|
-
|
|
683
|
+
const isError = chunk.toString().indexOf('[panic]') !== -1 ||
|
|
684
|
+
chunk.toString().indexOf('[error]') !== -1 ||
|
|
685
|
+
chunk.toString().indexOf('[fatal]') !== -1;
|
|
686
|
+
if (this.parameters[0].debug && !isError) {
|
|
488
687
|
this.log.debug(this.name, 'ffmpeg log message:\n' + chunk.toString());
|
|
489
688
|
}
|
|
689
|
+
else if (isError) {
|
|
690
|
+
this.log.error(this.name, 'ffmpeg log message:\n' + chunk.toString());
|
|
691
|
+
}
|
|
490
692
|
});
|
|
491
693
|
const killTimeout = setTimeout(() => {
|
|
492
694
|
this.stop();
|
|
@@ -516,6 +718,95 @@ class FFmpeg extends events_1.default {
|
|
|
516
718
|
}
|
|
517
719
|
});
|
|
518
720
|
}
|
|
721
|
+
async startFragmentedMP4Session() {
|
|
722
|
+
this.starttime = Date.now();
|
|
723
|
+
this.progress = new FFmpegProgress(this.parameters[0].progressPort);
|
|
724
|
+
this.progress.on('progress started', this.onProgressStarted.bind(this));
|
|
725
|
+
const port = await (0, pick_port_1.default)({
|
|
726
|
+
type: 'tcp',
|
|
727
|
+
ip: '0.0.0.0',
|
|
728
|
+
reserveTimeout: 15,
|
|
729
|
+
});
|
|
730
|
+
return new Promise((resolve, reject) => {
|
|
731
|
+
const server = net_1.default.createServer((socket) => {
|
|
732
|
+
server.close();
|
|
733
|
+
resolve({
|
|
734
|
+
socket: socket,
|
|
735
|
+
process: this.process,
|
|
736
|
+
generator: this.parseFragmentedMP4(socket),
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
server.listen(port, () => {
|
|
740
|
+
this.parameters[0].setOutput(`tcp://127.0.0.1:${port}`);
|
|
741
|
+
const processArgs = FFmpegParameters.getRecordingArguments(this.parameters);
|
|
742
|
+
this.log.debug(this.name, 'Stream command: ' + this.ffmpegExec + ' ' + processArgs.join(' '));
|
|
743
|
+
this.parameters.forEach((p) => {
|
|
744
|
+
this.log.info(this.name, p.getStreamStartText());
|
|
745
|
+
});
|
|
746
|
+
this.process = (0, child_process_1.spawn)(this.ffmpegExec, processArgs.join(' ').split(/\s+/), { env: process.env });
|
|
747
|
+
this.stdin = this.process.stdin;
|
|
748
|
+
this.stdout = this.process.stdout;
|
|
749
|
+
this.process.stderr.on('data', (chunk) => {
|
|
750
|
+
const isError = chunk.toString().indexOf('[panic]') !== -1 ||
|
|
751
|
+
chunk.toString().indexOf('[error]') !== -1 ||
|
|
752
|
+
chunk.toString().indexOf('[fatal]') !== -1;
|
|
753
|
+
if (this.parameters[0].debug && !isError) {
|
|
754
|
+
this.log.debug(this.name, 'ffmpeg log message:\n' + chunk.toString());
|
|
755
|
+
}
|
|
756
|
+
else if (isError) {
|
|
757
|
+
this.log.error(this.name, 'ffmpeg log message:\n' + chunk.toString());
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
this.process.on('error', this.onProcessError.bind(this));
|
|
761
|
+
this.process.on('exit', this.onProcessExit.bind(this));
|
|
762
|
+
});
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
async *parseFragmentedMP4(socket) {
|
|
766
|
+
while (true) {
|
|
767
|
+
const header = await this.readLength(socket, 8);
|
|
768
|
+
const length = header.readInt32BE(0) - 8;
|
|
769
|
+
const type = header.slice(4).toString();
|
|
770
|
+
const data = await this.readLength(socket, length);
|
|
771
|
+
yield {
|
|
772
|
+
header,
|
|
773
|
+
length,
|
|
774
|
+
type,
|
|
775
|
+
data,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
async readLength(socket, length) {
|
|
780
|
+
if (length <= 0) {
|
|
781
|
+
return Buffer.alloc(0);
|
|
782
|
+
}
|
|
783
|
+
const value = socket.read(length);
|
|
784
|
+
if (value) {
|
|
785
|
+
return value;
|
|
786
|
+
}
|
|
787
|
+
return new Promise((resolve, reject) => {
|
|
788
|
+
const readHandler = () => {
|
|
789
|
+
const value = socket.read(length);
|
|
790
|
+
if (value) {
|
|
791
|
+
cleanup();
|
|
792
|
+
resolve(value);
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
const endHandler = () => {
|
|
796
|
+
cleanup();
|
|
797
|
+
reject(new Error(`FFMPEG socket closed during read for ${length} bytes!`));
|
|
798
|
+
};
|
|
799
|
+
const cleanup = () => {
|
|
800
|
+
socket.removeListener('readable', readHandler);
|
|
801
|
+
socket.removeListener('close', endHandler);
|
|
802
|
+
};
|
|
803
|
+
if (!socket) {
|
|
804
|
+
throw new Error('FFMPEG socket is closed now!');
|
|
805
|
+
}
|
|
806
|
+
socket.on('readable', readHandler);
|
|
807
|
+
socket.on('close', endHandler);
|
|
808
|
+
});
|
|
809
|
+
}
|
|
519
810
|
stop() {
|
|
520
811
|
var _a, _b, _c;
|
|
521
812
|
let usesStdIn = false;
|
|
@@ -563,7 +854,8 @@ class FFmpeg extends events_1.default {
|
|
|
563
854
|
}
|
|
564
855
|
}
|
|
565
856
|
else {
|
|
566
|
-
this.
|
|
857
|
+
this.emit('error', message + ' (Error)');
|
|
858
|
+
// this.log.error(this.name, message + ' (Error)');
|
|
567
859
|
}
|
|
568
860
|
}
|
|
569
861
|
}
|