@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
package/dist/cli/rtsp-server.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
BaichuanRtspServer,
|
|
4
4
|
ReolinkBaichuanApi,
|
|
5
5
|
autoDetectDeviceType
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-UHFJPQA4.js";
|
|
7
7
|
import {
|
|
8
8
|
__require
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-DEOMUWBN.js";
|
|
10
10
|
|
|
11
11
|
// src/cli/rtsp-server.ts
|
|
12
12
|
function parseArgs() {
|
package/dist/index.cjs
CHANGED
|
@@ -5641,7 +5641,7 @@ async function captureModelFixtures(params) {
|
|
|
5641
5641
|
() => api.getDualLensChannelInfo(channel),
|
|
5642
5642
|
(v) => writeJsonSafe(path4.join(outDir, "dual-lens-info.json"), v)
|
|
5643
5643
|
);
|
|
5644
|
-
await capture("streamCombinationTest", async () => {
|
|
5644
|
+
if (!params.skipStreamCombinationTest) await capture("streamCombinationTest", async () => {
|
|
5645
5645
|
let dualLensInfo;
|
|
5646
5646
|
try {
|
|
5647
5647
|
dualLensInfo = await api.getDualLensChannelInfo(channel);
|
|
@@ -13410,6 +13410,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
13410
13410
|
flow;
|
|
13411
13411
|
deviceId;
|
|
13412
13412
|
dedicatedSessionRelease;
|
|
13413
|
+
externalListener;
|
|
13413
13414
|
// Authentication
|
|
13414
13415
|
authCredentials = [];
|
|
13415
13416
|
requireAuth;
|
|
@@ -13452,6 +13453,10 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
13452
13453
|
// Shared native stream fan-out (single camera stream, multiple RTSP clients)
|
|
13453
13454
|
nativeFanout = null;
|
|
13454
13455
|
noClientAutoStopTimer;
|
|
13456
|
+
/** After last RTSP client; 0 = never auto-stop native stream. */
|
|
13457
|
+
nativeStreamIdleStopMs;
|
|
13458
|
+
/** Primed-but-no-PLAY timeout; 0 = disabled. */
|
|
13459
|
+
nativeStreamPrimeIdleStopMs;
|
|
13455
13460
|
// Prebuffer: rolling ring of recent video frames for IDR-aligned fast startup.
|
|
13456
13461
|
// When a new client connects while the stream is already running it does not need
|
|
13457
13462
|
// to wait up to one full GOP interval for the next keyframe — we replay frames
|
|
@@ -13577,6 +13582,9 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
13577
13582
|
this.logger = options.logger ?? console;
|
|
13578
13583
|
this.tcpRtpFraming = options.tcpRtpFraming ?? "rfc4571";
|
|
13579
13584
|
this.deviceId = options.deviceId;
|
|
13585
|
+
this.externalListener = options.externalListener ?? false;
|
|
13586
|
+
this.nativeStreamIdleStopMs = options.nativeStreamIdleStopMs ?? 3e4;
|
|
13587
|
+
this.nativeStreamPrimeIdleStopMs = options.nativeStreamPrimeIdleStopMs ?? (this.nativeStreamIdleStopMs > 0 ? 15e3 : 0);
|
|
13580
13588
|
this.authCredentials = options.credentials ?? [];
|
|
13581
13589
|
this.requireAuth = options.requireAuth ?? this.authCredentials.length > 0;
|
|
13582
13590
|
const transport = this.api.client.getTransport();
|
|
@@ -13707,41 +13715,56 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
13707
13715
|
this.streamMetadata = { frameRate: 25 };
|
|
13708
13716
|
this.setFlowVideoType("H264", "metadata unavailable");
|
|
13709
13717
|
}
|
|
13710
|
-
this.
|
|
13711
|
-
this.
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
this.
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13718
|
+
if (!this.externalListener) {
|
|
13719
|
+
this.clientConnectionServer = net2.createServer((socket) => {
|
|
13720
|
+
this.handleRtspConnection(socket);
|
|
13721
|
+
});
|
|
13722
|
+
await new Promise((resolve, reject) => {
|
|
13723
|
+
this.clientConnectionServer.listen(
|
|
13724
|
+
this.listenPort,
|
|
13725
|
+
this.listenHost,
|
|
13726
|
+
() => {
|
|
13727
|
+
const address = this.clientConnectionServer.address();
|
|
13728
|
+
if (address && typeof address === "object" && "port" in address) {
|
|
13729
|
+
this.listenPort = address.port;
|
|
13730
|
+
}
|
|
13731
|
+
resolve();
|
|
13721
13732
|
}
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
reject(error);
|
|
13733
|
+
);
|
|
13734
|
+
this.clientConnectionServer.on("error", (error) => {
|
|
13735
|
+
reject(error);
|
|
13736
|
+
});
|
|
13727
13737
|
});
|
|
13728
|
-
}
|
|
13738
|
+
}
|
|
13729
13739
|
this.active = true;
|
|
13730
13740
|
this.logger.info(
|
|
13731
13741
|
`[BaichuanRtspServer] RTSP server started on ${this.listenHost}:${this.listenPort}, path: ${this.path}`
|
|
13732
13742
|
);
|
|
13733
13743
|
}
|
|
13744
|
+
/**
|
|
13745
|
+
* Accept an externally-routed RTSP connection.
|
|
13746
|
+
* Used in directHandoff mode where RtspProxyServer routes sockets here.
|
|
13747
|
+
* @param socket - The client TCP socket (already authenticated by proxy)
|
|
13748
|
+
* @param initialBuffer - Any bytes already read during path parsing/auth
|
|
13749
|
+
*/
|
|
13750
|
+
acceptConnection(socket, initialBuffer) {
|
|
13751
|
+
if (!this.active) {
|
|
13752
|
+
socket.end("RTSP/1.0 503 Service Unavailable\r\n\r\n");
|
|
13753
|
+
return;
|
|
13754
|
+
}
|
|
13755
|
+
this.handleRtspConnection(socket, initialBuffer);
|
|
13756
|
+
}
|
|
13734
13757
|
/**
|
|
13735
13758
|
* Handle RTSP connection from a client.
|
|
13736
13759
|
*/
|
|
13737
|
-
handleRtspConnection(socket) {
|
|
13760
|
+
handleRtspConnection(socket, initialBuffer) {
|
|
13738
13761
|
const clientId = `${socket.remoteAddress}:${socket.remotePort}`;
|
|
13739
13762
|
const connectTime = Date.now();
|
|
13740
13763
|
this.logger.info(
|
|
13741
13764
|
`[rebroadcast] client connected client=${clientId} path=${this.path} profile=${this.profile} channel=${this.channel}`
|
|
13742
13765
|
);
|
|
13743
13766
|
let sessionId = "";
|
|
13744
|
-
let buffer = Buffer.alloc(0);
|
|
13767
|
+
let buffer = initialBuffer ?? Buffer.alloc(0);
|
|
13745
13768
|
let clientFfmpeg;
|
|
13746
13769
|
let useTcpInterleaved = false;
|
|
13747
13770
|
let clientUdpSocket = null;
|
|
@@ -13826,8 +13849,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
13826
13849
|
}
|
|
13827
13850
|
cleanup();
|
|
13828
13851
|
});
|
|
13829
|
-
|
|
13830
|
-
buffer = Buffer.concat([buffer, data]);
|
|
13852
|
+
const processBuffer = async () => {
|
|
13831
13853
|
while (buffer.includes("\r\n\r\n")) {
|
|
13832
13854
|
const endIndex = buffer.indexOf("\r\n\r\n");
|
|
13833
13855
|
const requestText = buffer.subarray(0, endIndex).toString();
|
|
@@ -14102,7 +14124,14 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
14102
14124
|
sendResponse(501, "Not Implemented");
|
|
14103
14125
|
}
|
|
14104
14126
|
}
|
|
14127
|
+
};
|
|
14128
|
+
socket.on("data", (data) => {
|
|
14129
|
+
buffer = Buffer.concat([buffer, data]);
|
|
14130
|
+
void processBuffer();
|
|
14105
14131
|
});
|
|
14132
|
+
if (buffer.includes("\r\n\r\n")) {
|
|
14133
|
+
void processBuffer();
|
|
14134
|
+
}
|
|
14106
14135
|
}
|
|
14107
14136
|
/**
|
|
14108
14137
|
* Generate SDP (Session Description Protocol) for RTSP DESCRIBE.
|
|
@@ -15070,34 +15099,42 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
15070
15099
|
res.seenFirstVideoKeyframe = false;
|
|
15071
15100
|
res.rtpSentVideoConfig = false;
|
|
15072
15101
|
}
|
|
15073
|
-
if (this.dedicatedSessionRelease) {
|
|
15074
|
-
const release = this.dedicatedSessionRelease;
|
|
15075
|
-
this.dedicatedSessionRelease = void 0;
|
|
15076
|
-
release().catch(() => {
|
|
15077
|
-
});
|
|
15078
|
-
}
|
|
15079
15102
|
this.logger.info(
|
|
15080
15103
|
`[rebroadcast] native stream ended (camera sleeping or connection lost) profile=${this.profile} channel=${this.channel} clients=${this.connectedClients.size}`
|
|
15081
15104
|
);
|
|
15082
|
-
|
|
15083
|
-
this.
|
|
15084
|
-
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15105
|
+
const releaseAndRestart = async () => {
|
|
15106
|
+
if (this.dedicatedSessionRelease) {
|
|
15107
|
+
const release = this.dedicatedSessionRelease;
|
|
15108
|
+
this.dedicatedSessionRelease = void 0;
|
|
15109
|
+
try {
|
|
15110
|
+
await release();
|
|
15111
|
+
} catch {
|
|
15112
|
+
}
|
|
15113
|
+
}
|
|
15114
|
+
if (this.connectedClients.size > 0) {
|
|
15115
|
+
this.logger.info(
|
|
15116
|
+
`[rebroadcast] restarting native stream for ${this.connectedClients.size} active client(s)`
|
|
15117
|
+
);
|
|
15118
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
15119
|
+
void this.startNativeStream();
|
|
15120
|
+
}
|
|
15121
|
+
};
|
|
15122
|
+
void releaseAndRestart();
|
|
15088
15123
|
}
|
|
15089
15124
|
});
|
|
15090
15125
|
this.nativeFanout.start();
|
|
15091
15126
|
this.clearNoClientAutoStopTimer();
|
|
15092
|
-
this.
|
|
15093
|
-
|
|
15094
|
-
this.
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15127
|
+
if (this.nativeStreamPrimeIdleStopMs > 0) {
|
|
15128
|
+
this.noClientAutoStopTimer = setTimeout(() => {
|
|
15129
|
+
if (this.connectedClients.size === 0) {
|
|
15130
|
+
this.rtspDebugLog(
|
|
15131
|
+
`Auto-stopping primed native stream (no clients connected)`
|
|
15132
|
+
);
|
|
15133
|
+
void this.stopNativeStream();
|
|
15134
|
+
}
|
|
15135
|
+
}, this.nativeStreamPrimeIdleStopMs);
|
|
15136
|
+
this.noClientAutoStopTimer?.unref?.();
|
|
15137
|
+
}
|
|
15101
15138
|
}
|
|
15102
15139
|
markFirstFrameReceived() {
|
|
15103
15140
|
if (!this.firstFrameReceived && this.firstFrameResolve) {
|
|
@@ -15172,12 +15209,14 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
15172
15209
|
this.emit("clientDisconnected", clientId);
|
|
15173
15210
|
if (this.connectedClients.size === 0) {
|
|
15174
15211
|
this.clearNoClientAutoStopTimer();
|
|
15175
|
-
this.
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15212
|
+
if (this.nativeStreamIdleStopMs > 0) {
|
|
15213
|
+
this.noClientAutoStopTimer = setTimeout(() => {
|
|
15214
|
+
if (this.connectedClients.size === 0) {
|
|
15215
|
+
void this.stopNativeStream();
|
|
15216
|
+
}
|
|
15217
|
+
}, this.nativeStreamIdleStopMs);
|
|
15218
|
+
this.noClientAutoStopTimer?.unref?.();
|
|
15219
|
+
}
|
|
15181
15220
|
}
|
|
15182
15221
|
}
|
|
15183
15222
|
}
|
|
@@ -15308,6 +15347,31 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events4.E
|
|
|
15308
15347
|
getClientCount() {
|
|
15309
15348
|
return this.connectedClients.size;
|
|
15310
15349
|
}
|
|
15350
|
+
/**
|
|
15351
|
+
* Subscribe to the raw native stream for diagnostic purposes.
|
|
15352
|
+
* The subscriber receives the same frames as RTSP clients.
|
|
15353
|
+
* Counts as a "consumer" for lifecycle — prevents auto-stop while subscribed.
|
|
15354
|
+
* If the native stream is not active, starts it automatically.
|
|
15355
|
+
*/
|
|
15356
|
+
async subscribeDiagnostic(id) {
|
|
15357
|
+
this.connectedClients.add(`diag:${id}`);
|
|
15358
|
+
if (!this.nativeStreamActive) {
|
|
15359
|
+
await this.startNativeStream();
|
|
15360
|
+
}
|
|
15361
|
+
return this.nativeFanout.subscribe(`diag:${id}`);
|
|
15362
|
+
}
|
|
15363
|
+
/**
|
|
15364
|
+
* Unsubscribe a diagnostic session.
|
|
15365
|
+
*/
|
|
15366
|
+
unsubscribeDiagnostic(id) {
|
|
15367
|
+
this.removeClient(`diag:${id}`);
|
|
15368
|
+
}
|
|
15369
|
+
/**
|
|
15370
|
+
* Returns detected audio metadata (available after first audio frame).
|
|
15371
|
+
*/
|
|
15372
|
+
getAudioInfo() {
|
|
15373
|
+
return this.audioInfo;
|
|
15374
|
+
}
|
|
15311
15375
|
};
|
|
15312
15376
|
|
|
15313
15377
|
// src/reolink/baichuan/ReolinkBaichuanApi.ts
|