@apocaliss92/nodelink-js 0.4.1 → 0.4.3
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 +56 -603
- package/dist/{DiagnosticsTools-XIIYZDXL.js → DiagnosticsTools-55PR4WFD.js} +2 -2
- package/dist/{chunk-DUHWTZ7U.js → chunk-DEOMUWBN.js} +2 -2
- package/dist/chunk-DEOMUWBN.js.map +1 -0
- package/dist/{chunk-SDRNJQ5U.js → chunk-UHFJPQA4.js} +116 -52
- package/dist/chunk-UHFJPQA4.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +113 -49
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +2 -2
- package/dist/index.cjs +113 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -9
- package/dist/index.d.ts +66 -7
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-DUHWTZ7U.js.map +0 -1
- package/dist/chunk-SDRNJQ5U.js.map +0 -1
- /package/dist/{DiagnosticsTools-XIIYZDXL.js.map → DiagnosticsTools-55PR4WFD.js.map} +0 -0
|
@@ -144,7 +144,7 @@ import {
|
|
|
144
144
|
talkTraceLog,
|
|
145
145
|
traceLog,
|
|
146
146
|
xmlEscape
|
|
147
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-DEOMUWBN.js";
|
|
148
148
|
|
|
149
149
|
// src/protocol/framing.ts
|
|
150
150
|
function encodeHeader(h) {
|
|
@@ -5518,6 +5518,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
5518
5518
|
flow;
|
|
5519
5519
|
deviceId;
|
|
5520
5520
|
dedicatedSessionRelease;
|
|
5521
|
+
externalListener;
|
|
5521
5522
|
// Authentication
|
|
5522
5523
|
authCredentials = [];
|
|
5523
5524
|
requireAuth;
|
|
@@ -5560,6 +5561,10 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
5560
5561
|
// Shared native stream fan-out (single camera stream, multiple RTSP clients)
|
|
5561
5562
|
nativeFanout = null;
|
|
5562
5563
|
noClientAutoStopTimer;
|
|
5564
|
+
/** After last RTSP client; 0 = never auto-stop native stream. */
|
|
5565
|
+
nativeStreamIdleStopMs;
|
|
5566
|
+
/** Primed-but-no-PLAY timeout; 0 = disabled. */
|
|
5567
|
+
nativeStreamPrimeIdleStopMs;
|
|
5563
5568
|
// Prebuffer: rolling ring of recent video frames for IDR-aligned fast startup.
|
|
5564
5569
|
// When a new client connects while the stream is already running it does not need
|
|
5565
5570
|
// to wait up to one full GOP interval for the next keyframe — we replay frames
|
|
@@ -5685,6 +5690,9 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
5685
5690
|
this.logger = options.logger ?? console;
|
|
5686
5691
|
this.tcpRtpFraming = options.tcpRtpFraming ?? "rfc4571";
|
|
5687
5692
|
this.deviceId = options.deviceId;
|
|
5693
|
+
this.externalListener = options.externalListener ?? false;
|
|
5694
|
+
this.nativeStreamIdleStopMs = options.nativeStreamIdleStopMs ?? 3e4;
|
|
5695
|
+
this.nativeStreamPrimeIdleStopMs = options.nativeStreamPrimeIdleStopMs ?? (this.nativeStreamIdleStopMs > 0 ? 15e3 : 0);
|
|
5688
5696
|
this.authCredentials = options.credentials ?? [];
|
|
5689
5697
|
this.requireAuth = options.requireAuth ?? this.authCredentials.length > 0;
|
|
5690
5698
|
const transport = this.api.client.getTransport();
|
|
@@ -5815,41 +5823,56 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
5815
5823
|
this.streamMetadata = { frameRate: 25 };
|
|
5816
5824
|
this.setFlowVideoType("H264", "metadata unavailable");
|
|
5817
5825
|
}
|
|
5818
|
-
this.
|
|
5819
|
-
this.
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
this.
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5826
|
+
if (!this.externalListener) {
|
|
5827
|
+
this.clientConnectionServer = net2.createServer((socket) => {
|
|
5828
|
+
this.handleRtspConnection(socket);
|
|
5829
|
+
});
|
|
5830
|
+
await new Promise((resolve, reject) => {
|
|
5831
|
+
this.clientConnectionServer.listen(
|
|
5832
|
+
this.listenPort,
|
|
5833
|
+
this.listenHost,
|
|
5834
|
+
() => {
|
|
5835
|
+
const address = this.clientConnectionServer.address();
|
|
5836
|
+
if (address && typeof address === "object" && "port" in address) {
|
|
5837
|
+
this.listenPort = address.port;
|
|
5838
|
+
}
|
|
5839
|
+
resolve();
|
|
5829
5840
|
}
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
reject(error);
|
|
5841
|
+
);
|
|
5842
|
+
this.clientConnectionServer.on("error", (error) => {
|
|
5843
|
+
reject(error);
|
|
5844
|
+
});
|
|
5835
5845
|
});
|
|
5836
|
-
}
|
|
5846
|
+
}
|
|
5837
5847
|
this.active = true;
|
|
5838
5848
|
this.logger.info(
|
|
5839
5849
|
`[BaichuanRtspServer] RTSP server started on ${this.listenHost}:${this.listenPort}, path: ${this.path}`
|
|
5840
5850
|
);
|
|
5841
5851
|
}
|
|
5852
|
+
/**
|
|
5853
|
+
* Accept an externally-routed RTSP connection.
|
|
5854
|
+
* Used in directHandoff mode where RtspProxyServer routes sockets here.
|
|
5855
|
+
* @param socket - The client TCP socket (already authenticated by proxy)
|
|
5856
|
+
* @param initialBuffer - Any bytes already read during path parsing/auth
|
|
5857
|
+
*/
|
|
5858
|
+
acceptConnection(socket, initialBuffer) {
|
|
5859
|
+
if (!this.active) {
|
|
5860
|
+
socket.end("RTSP/1.0 503 Service Unavailable\r\n\r\n");
|
|
5861
|
+
return;
|
|
5862
|
+
}
|
|
5863
|
+
this.handleRtspConnection(socket, initialBuffer);
|
|
5864
|
+
}
|
|
5842
5865
|
/**
|
|
5843
5866
|
* Handle RTSP connection from a client.
|
|
5844
5867
|
*/
|
|
5845
|
-
handleRtspConnection(socket) {
|
|
5868
|
+
handleRtspConnection(socket, initialBuffer) {
|
|
5846
5869
|
const clientId = `${socket.remoteAddress}:${socket.remotePort}`;
|
|
5847
5870
|
const connectTime = Date.now();
|
|
5848
5871
|
this.logger.info(
|
|
5849
5872
|
`[rebroadcast] client connected client=${clientId} path=${this.path} profile=${this.profile} channel=${this.channel}`
|
|
5850
5873
|
);
|
|
5851
5874
|
let sessionId = "";
|
|
5852
|
-
let buffer = Buffer.alloc(0);
|
|
5875
|
+
let buffer = initialBuffer ?? Buffer.alloc(0);
|
|
5853
5876
|
let clientFfmpeg;
|
|
5854
5877
|
let useTcpInterleaved = false;
|
|
5855
5878
|
let clientUdpSocket = null;
|
|
@@ -5934,8 +5957,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
5934
5957
|
}
|
|
5935
5958
|
cleanup();
|
|
5936
5959
|
});
|
|
5937
|
-
|
|
5938
|
-
buffer = Buffer.concat([buffer, data]);
|
|
5960
|
+
const processBuffer = async () => {
|
|
5939
5961
|
while (buffer.includes("\r\n\r\n")) {
|
|
5940
5962
|
const endIndex = buffer.indexOf("\r\n\r\n");
|
|
5941
5963
|
const requestText = buffer.subarray(0, endIndex).toString();
|
|
@@ -6210,7 +6232,14 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
6210
6232
|
sendResponse(501, "Not Implemented");
|
|
6211
6233
|
}
|
|
6212
6234
|
}
|
|
6235
|
+
};
|
|
6236
|
+
socket.on("data", (data) => {
|
|
6237
|
+
buffer = Buffer.concat([buffer, data]);
|
|
6238
|
+
void processBuffer();
|
|
6213
6239
|
});
|
|
6240
|
+
if (buffer.includes("\r\n\r\n")) {
|
|
6241
|
+
void processBuffer();
|
|
6242
|
+
}
|
|
6214
6243
|
}
|
|
6215
6244
|
/**
|
|
6216
6245
|
* Generate SDP (Session Description Protocol) for RTSP DESCRIBE.
|
|
@@ -7178,34 +7207,42 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
7178
7207
|
res.seenFirstVideoKeyframe = false;
|
|
7179
7208
|
res.rtpSentVideoConfig = false;
|
|
7180
7209
|
}
|
|
7181
|
-
if (this.dedicatedSessionRelease) {
|
|
7182
|
-
const release = this.dedicatedSessionRelease;
|
|
7183
|
-
this.dedicatedSessionRelease = void 0;
|
|
7184
|
-
release().catch(() => {
|
|
7185
|
-
});
|
|
7186
|
-
}
|
|
7187
7210
|
this.logger.info(
|
|
7188
7211
|
`[rebroadcast] native stream ended (camera sleeping or connection lost) profile=${this.profile} channel=${this.channel} clients=${this.connectedClients.size}`
|
|
7189
7212
|
);
|
|
7190
|
-
|
|
7191
|
-
this.
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7213
|
+
const releaseAndRestart = async () => {
|
|
7214
|
+
if (this.dedicatedSessionRelease) {
|
|
7215
|
+
const release = this.dedicatedSessionRelease;
|
|
7216
|
+
this.dedicatedSessionRelease = void 0;
|
|
7217
|
+
try {
|
|
7218
|
+
await release();
|
|
7219
|
+
} catch {
|
|
7220
|
+
}
|
|
7221
|
+
}
|
|
7222
|
+
if (this.connectedClients.size > 0) {
|
|
7223
|
+
this.logger.info(
|
|
7224
|
+
`[rebroadcast] restarting native stream for ${this.connectedClients.size} active client(s)`
|
|
7225
|
+
);
|
|
7226
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
7227
|
+
void this.startNativeStream();
|
|
7228
|
+
}
|
|
7229
|
+
};
|
|
7230
|
+
void releaseAndRestart();
|
|
7196
7231
|
}
|
|
7197
7232
|
});
|
|
7198
7233
|
this.nativeFanout.start();
|
|
7199
7234
|
this.clearNoClientAutoStopTimer();
|
|
7200
|
-
this.
|
|
7201
|
-
|
|
7202
|
-
this.
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7235
|
+
if (this.nativeStreamPrimeIdleStopMs > 0) {
|
|
7236
|
+
this.noClientAutoStopTimer = setTimeout(() => {
|
|
7237
|
+
if (this.connectedClients.size === 0) {
|
|
7238
|
+
this.rtspDebugLog(
|
|
7239
|
+
`Auto-stopping primed native stream (no clients connected)`
|
|
7240
|
+
);
|
|
7241
|
+
void this.stopNativeStream();
|
|
7242
|
+
}
|
|
7243
|
+
}, this.nativeStreamPrimeIdleStopMs);
|
|
7244
|
+
this.noClientAutoStopTimer?.unref?.();
|
|
7245
|
+
}
|
|
7209
7246
|
}
|
|
7210
7247
|
markFirstFrameReceived() {
|
|
7211
7248
|
if (!this.firstFrameReceived && this.firstFrameResolve) {
|
|
@@ -7280,12 +7317,14 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
7280
7317
|
this.emit("clientDisconnected", clientId);
|
|
7281
7318
|
if (this.connectedClients.size === 0) {
|
|
7282
7319
|
this.clearNoClientAutoStopTimer();
|
|
7283
|
-
this.
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7320
|
+
if (this.nativeStreamIdleStopMs > 0) {
|
|
7321
|
+
this.noClientAutoStopTimer = setTimeout(() => {
|
|
7322
|
+
if (this.connectedClients.size === 0) {
|
|
7323
|
+
void this.stopNativeStream();
|
|
7324
|
+
}
|
|
7325
|
+
}, this.nativeStreamIdleStopMs);
|
|
7326
|
+
this.noClientAutoStopTimer?.unref?.();
|
|
7327
|
+
}
|
|
7289
7328
|
}
|
|
7290
7329
|
}
|
|
7291
7330
|
}
|
|
@@ -7416,6 +7455,31 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends EventEmitter3 {
|
|
|
7416
7455
|
getClientCount() {
|
|
7417
7456
|
return this.connectedClients.size;
|
|
7418
7457
|
}
|
|
7458
|
+
/**
|
|
7459
|
+
* Subscribe to the raw native stream for diagnostic purposes.
|
|
7460
|
+
* The subscriber receives the same frames as RTSP clients.
|
|
7461
|
+
* Counts as a "consumer" for lifecycle — prevents auto-stop while subscribed.
|
|
7462
|
+
* If the native stream is not active, starts it automatically.
|
|
7463
|
+
*/
|
|
7464
|
+
async subscribeDiagnostic(id) {
|
|
7465
|
+
this.connectedClients.add(`diag:${id}`);
|
|
7466
|
+
if (!this.nativeStreamActive) {
|
|
7467
|
+
await this.startNativeStream();
|
|
7468
|
+
}
|
|
7469
|
+
return this.nativeFanout.subscribe(`diag:${id}`);
|
|
7470
|
+
}
|
|
7471
|
+
/**
|
|
7472
|
+
* Unsubscribe a diagnostic session.
|
|
7473
|
+
*/
|
|
7474
|
+
unsubscribeDiagnostic(id) {
|
|
7475
|
+
this.removeClient(`diag:${id}`);
|
|
7476
|
+
}
|
|
7477
|
+
/**
|
|
7478
|
+
* Returns detected audio metadata (available after first audio frame).
|
|
7479
|
+
*/
|
|
7480
|
+
getAudioInfo() {
|
|
7481
|
+
return this.audioInfo;
|
|
7482
|
+
}
|
|
7419
7483
|
};
|
|
7420
7484
|
|
|
7421
7485
|
// src/reolink/baichuan/capabilities.ts
|
|
@@ -17818,7 +17882,7 @@ ${xml}`
|
|
|
17818
17882
|
* @returns Test results for all stream types and profiles
|
|
17819
17883
|
*/
|
|
17820
17884
|
async testChannelStreams(channel, logger) {
|
|
17821
|
-
const { testChannelStreams } = await import("./DiagnosticsTools-
|
|
17885
|
+
const { testChannelStreams } = await import("./DiagnosticsTools-55PR4WFD.js");
|
|
17822
17886
|
return await testChannelStreams({
|
|
17823
17887
|
api: this,
|
|
17824
17888
|
channel: this.normalizeChannel(channel),
|
|
@@ -17834,7 +17898,7 @@ ${xml}`
|
|
|
17834
17898
|
* @returns Complete diagnostics for all channels and streams
|
|
17835
17899
|
*/
|
|
17836
17900
|
async collectMultifocalDiagnostics(logger) {
|
|
17837
|
-
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-
|
|
17901
|
+
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-55PR4WFD.js");
|
|
17838
17902
|
return await collectMultifocalDiagnostics({
|
|
17839
17903
|
api: this,
|
|
17840
17904
|
logger
|
|
@@ -21516,4 +21580,4 @@ export {
|
|
|
21516
21580
|
isTcpFailureThatShouldFallbackToUdp,
|
|
21517
21581
|
autoDetectDeviceType
|
|
21518
21582
|
};
|
|
21519
|
-
//# sourceMappingURL=chunk-
|
|
21583
|
+
//# sourceMappingURL=chunk-UHFJPQA4.js.map
|