@apocaliss92/nodelink-js 0.4.5 → 0.4.6
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/{DiagnosticsTools-55PR4WFD.js → DiagnosticsTools-UMN4C7SY.js} +2 -2
- package/dist/{chunk-WDFKIHM5.js → chunk-F2Y5U3YP.js} +86 -13
- package/dist/chunk-F2Y5U3YP.js.map +1 -0
- package/dist/{chunk-DEOMUWBN.js → chunk-TR3V5FTO.js} +15 -1
- package/dist/chunk-TR3V5FTO.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +96 -9
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +2 -2
- package/dist/index.cjs +125 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +31 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-DEOMUWBN.js.map +0 -1
- package/dist/chunk-WDFKIHM5.js.map +0 -1
- /package/dist/{DiagnosticsTools-55PR4WFD.js.map → DiagnosticsTools-UMN4C7SY.js.map} +0 -0
package/dist/cli/rtsp-server.cjs
CHANGED
|
@@ -1567,6 +1567,19 @@ var init_BaichuanVideoStream = __esm({
|
|
|
1567
1567
|
// Stateful AES decryptor for fragmented BcMedia packets (full_aes mode)
|
|
1568
1568
|
// In CFB mode, continuation frames must use the cipher state from previous frames.
|
|
1569
1569
|
aesStreamDecryptor = null;
|
|
1570
|
+
/**
|
|
1571
|
+
* Pending startup error stashed when emitSafeError is called before any
|
|
1572
|
+
* "error" listener is registered (e.g. camera returns 400 during start()).
|
|
1573
|
+
* The rfc4571-server's waitForKeyframe can consume this immediately instead
|
|
1574
|
+
* of waiting for the full keyframe timeout.
|
|
1575
|
+
*/
|
|
1576
|
+
_pendingStartupError;
|
|
1577
|
+
/** Consume and clear any pending startup error. */
|
|
1578
|
+
consumePendingStartupError() {
|
|
1579
|
+
const err = this._pendingStartupError;
|
|
1580
|
+
this._pendingStartupError = void 0;
|
|
1581
|
+
return err;
|
|
1582
|
+
}
|
|
1570
1583
|
emitSafeError(err) {
|
|
1571
1584
|
if (!this.active) {
|
|
1572
1585
|
this.logger?.warn?.(
|
|
@@ -1578,6 +1591,7 @@ var init_BaichuanVideoStream = __esm({
|
|
|
1578
1591
|
this.logger?.warn?.(
|
|
1579
1592
|
`[BaichuanVideoStream] Unhandled stream error: ${err.message}`
|
|
1580
1593
|
);
|
|
1594
|
+
this._pendingStartupError = err;
|
|
1581
1595
|
return;
|
|
1582
1596
|
}
|
|
1583
1597
|
this.emit("error", err);
|
|
@@ -10657,6 +10671,9 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
10657
10671
|
resendTimer;
|
|
10658
10672
|
hbTimer;
|
|
10659
10673
|
discoveryTid;
|
|
10674
|
+
// Track discovery-phase timers so close() can cancel them even if
|
|
10675
|
+
// discovery is still in progress (prevents ERR_SOCKET_DGRAM_NOT_RUNNING).
|
|
10676
|
+
discoveryTimers = [];
|
|
10660
10677
|
acceptSent = false;
|
|
10661
10678
|
lastAcceptAtMs;
|
|
10662
10679
|
ackScheduled = false;
|
|
@@ -10705,9 +10722,31 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
10705
10722
|
});
|
|
10706
10723
|
sock.on("error", (e) => this.emit("error", e));
|
|
10707
10724
|
sock.on("close", () => this.emit("close"));
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10725
|
+
const portRange = Array.from({ length: 500 }, (_, i) => 53500 + i);
|
|
10726
|
+
for (let i = portRange.length - 1; i > 0; i--) {
|
|
10727
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
10728
|
+
[portRange[i], portRange[j]] = [portRange[j], portRange[i]];
|
|
10729
|
+
}
|
|
10730
|
+
let bound = false;
|
|
10731
|
+
for (const port of portRange) {
|
|
10732
|
+
try {
|
|
10733
|
+
await new Promise((resolve, reject) => {
|
|
10734
|
+
sock.once("error", reject);
|
|
10735
|
+
sock.bind(port, "0.0.0.0", () => {
|
|
10736
|
+
sock.removeListener("error", reject);
|
|
10737
|
+
resolve();
|
|
10738
|
+
});
|
|
10739
|
+
});
|
|
10740
|
+
bound = true;
|
|
10741
|
+
break;
|
|
10742
|
+
} catch {
|
|
10743
|
+
}
|
|
10744
|
+
}
|
|
10745
|
+
if (!bound) {
|
|
10746
|
+
await new Promise(
|
|
10747
|
+
(resolve) => sock.bind(0, "0.0.0.0", () => resolve())
|
|
10748
|
+
);
|
|
10749
|
+
}
|
|
10711
10750
|
if (this.opts.mode === "direct") {
|
|
10712
10751
|
this.remote = { host: this.opts.host, port: this.opts.port };
|
|
10713
10752
|
this.clientId = this.opts.clientId;
|
|
@@ -11127,7 +11166,24 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
11127
11166
|
BCUDP_DISCOVERY_PORT_LOCAL_ANY,
|
|
11128
11167
|
BCUDP_DISCOVERY_PORT_LOCAL_UID
|
|
11129
11168
|
];
|
|
11130
|
-
const
|
|
11169
|
+
const broadcastHosts = ["255.255.255.255"];
|
|
11170
|
+
const ifaces = (0, import_node_os.networkInterfaces)();
|
|
11171
|
+
for (const name of Object.keys(ifaces)) {
|
|
11172
|
+
const entries = ifaces[name];
|
|
11173
|
+
if (!entries) continue;
|
|
11174
|
+
for (const addr2 of entries) {
|
|
11175
|
+
if (addr2.family === "IPv4" && !addr2.internal && addr2.cidr) {
|
|
11176
|
+
const ipParts = addr2.address.split(".").map(Number);
|
|
11177
|
+
const maskParts = addr2.netmask.split(".").map(Number);
|
|
11178
|
+
if (ipParts.length === 4 && maskParts.length === 4) {
|
|
11179
|
+
const bcast = ipParts.map((octet, i) => octet | ~maskParts[i] & 255).join(".");
|
|
11180
|
+
if (!broadcastHosts.includes(bcast)) {
|
|
11181
|
+
broadcastHosts.push(bcast);
|
|
11182
|
+
}
|
|
11183
|
+
}
|
|
11184
|
+
}
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11131
11187
|
const directHost = (this.opts.directHost ?? "").trim();
|
|
11132
11188
|
const localMode = opts?.localMode ?? "local-broadcast";
|
|
11133
11189
|
const directFirstWindowMs = localMode === "local-direct" && directHost ? 3e3 : 0;
|
|
@@ -11154,6 +11210,7 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
11154
11210
|
)
|
|
11155
11211
|
);
|
|
11156
11212
|
}, discoveryTimeout);
|
|
11213
|
+
this.discoveryTimers.push(timeout);
|
|
11157
11214
|
let retryTimer;
|
|
11158
11215
|
let retryCount = 0;
|
|
11159
11216
|
let discoveredSid;
|
|
@@ -11330,11 +11387,11 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
11330
11387
|
if (directHost) {
|
|
11331
11388
|
if (directFirstWindowMs > 0 && elapsedMs < directFirstWindowMs)
|
|
11332
11389
|
return [directHost];
|
|
11333
|
-
return [directHost,
|
|
11390
|
+
return [directHost, ...broadcastHosts];
|
|
11334
11391
|
}
|
|
11335
|
-
return
|
|
11392
|
+
return broadcastHosts;
|
|
11336
11393
|
}
|
|
11337
|
-
return
|
|
11394
|
+
return broadcastHosts;
|
|
11338
11395
|
})();
|
|
11339
11396
|
for (const host of Array.from(new Set(hosts))) {
|
|
11340
11397
|
for (const port of ports) {
|
|
@@ -11342,8 +11399,7 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
11342
11399
|
sock.send(packet, port, host);
|
|
11343
11400
|
retryCount++;
|
|
11344
11401
|
this.emit("debug", "discovery_send", { retryCount, host, port });
|
|
11345
|
-
} catch
|
|
11346
|
-
this.emit("error", e instanceof Error ? e : new Error(String(e)));
|
|
11402
|
+
} catch {
|
|
11347
11403
|
}
|
|
11348
11404
|
}
|
|
11349
11405
|
}
|
|
@@ -11352,6 +11408,7 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
11352
11408
|
retryTimer = (0, import_node_timers.setInterval)(() => {
|
|
11353
11409
|
sendDiscovery();
|
|
11354
11410
|
}, retryInterval);
|
|
11411
|
+
this.discoveryTimers.push(retryTimer);
|
|
11355
11412
|
});
|
|
11356
11413
|
this.clientId = reply.cid;
|
|
11357
11414
|
this.cameraId = reply.did;
|
|
@@ -11668,6 +11725,10 @@ var BcUdpStream = class extends import_node_events3.EventEmitter {
|
|
|
11668
11725
|
this.ackTimer = void 0;
|
|
11669
11726
|
this.resendTimer = void 0;
|
|
11670
11727
|
this.hbTimer = void 0;
|
|
11728
|
+
for (const t of this.discoveryTimers) {
|
|
11729
|
+
clearInterval(t);
|
|
11730
|
+
}
|
|
11731
|
+
this.discoveryTimers = [];
|
|
11671
11732
|
const s = this.sock;
|
|
11672
11733
|
this.sock = void 0;
|
|
11673
11734
|
if (!s) return;
|
|
@@ -18077,6 +18138,20 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
18077
18138
|
const prefix = basename.substring(0, 10).toUpperCase();
|
|
18078
18139
|
return prefix.includes("S") ? "subStream" : "mainStream";
|
|
18079
18140
|
}
|
|
18141
|
+
/**
|
|
18142
|
+
* Stream profiles that the device explicitly rejected (response_code 400).
|
|
18143
|
+
* Keyed by `"ch:profile"` (e.g. `"0:ext"`). Once a profile is in this set
|
|
18144
|
+
* it is excluded from `buildVideoStreamOptions()` results and no further
|
|
18145
|
+
* start attempts are made until the API instance is recreated.
|
|
18146
|
+
*/
|
|
18147
|
+
_rejectedStreamProfiles = /* @__PURE__ */ new Set();
|
|
18148
|
+
/**
|
|
18149
|
+
* Check whether a stream profile was rejected by the device at runtime
|
|
18150
|
+
* (e.g. ext returned response_code 400).
|
|
18151
|
+
*/
|
|
18152
|
+
isStreamProfileRejected(channel, profile) {
|
|
18153
|
+
return this._rejectedStreamProfiles.has(`${channel}:${profile}`);
|
|
18154
|
+
}
|
|
18080
18155
|
/**
|
|
18081
18156
|
* Cache for buildVideoStreamOptions.
|
|
18082
18157
|
*
|
|
@@ -23201,6 +23276,16 @@ ${stderr}`)
|
|
|
23201
23276
|
}
|
|
23202
23277
|
if (!frame) frame = await targetClient.sendFrame(baseParams);
|
|
23203
23278
|
if (frame.header.responseCode !== 200) {
|
|
23279
|
+
if (frame.header.responseCode === 400) {
|
|
23280
|
+
const rejKey = `${ch}:${profile}`;
|
|
23281
|
+
if (!this._rejectedStreamProfiles.has(rejKey)) {
|
|
23282
|
+
this._rejectedStreamProfiles.add(rejKey);
|
|
23283
|
+
this.videoStreamOptionsCache.clear();
|
|
23284
|
+
this.logger?.warn?.(
|
|
23285
|
+
`[ReolinkBaichuanApi] Stream profile rejected by device: channel=${ch} profile=${profile} (response_code 400). This profile will be excluded from available streams. The camera may not support this stream profile with the current firmware.`
|
|
23286
|
+
);
|
|
23287
|
+
}
|
|
23288
|
+
}
|
|
23204
23289
|
throw new Error(
|
|
23205
23290
|
`Video stream request rejected (response_code ${frame.header.responseCode}). Expected response_code 200, camera returned ${frame.header.responseCode}`
|
|
23206
23291
|
);
|
|
@@ -25222,6 +25307,8 @@ ${xml}`
|
|
|
25222
25307
|
for (const metadata of params.metadatas) {
|
|
25223
25308
|
const profile = metadata.profile;
|
|
25224
25309
|
if (isMultiFocal && profile === "ext") continue;
|
|
25310
|
+
if (this._rejectedStreamProfiles.has(`${params.channel}:${profile}`))
|
|
25311
|
+
continue;
|
|
25225
25312
|
if (params.includeRtsp && profile !== "ext") {
|
|
25226
25313
|
const streamName = profile === "main" ? "main" : "sub";
|
|
25227
25314
|
pushRtsp({
|