@apocaliss92/nodelink-js 0.5.1 → 0.5.2
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/BaichuanVideoStream-OCLOM452.js +7 -0
- package/dist/{DiagnosticsTools-7BIWJDZS.js → DiagnosticsTools-K4MF2VXZ.js} +3 -3
- package/dist/{chunk-OJQLZETO.js → chunk-7HSTETZR.js} +409 -108
- package/dist/chunk-7HSTETZR.js.map +1 -0
- package/dist/{chunk-GVWJGQPT.js → chunk-MZUSWKF3.js} +5 -1
- package/dist/chunk-MZUSWKF3.js.map +1 -0
- package/dist/{chunk-VOPEOB4H.js → chunk-XDVBNZGR.js} +2 -2
- package/dist/cli/rtsp-server.cjs +403 -102
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +3 -3
- package/dist/index.cjs +410 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -1
- package/dist/index.d.ts +42 -0
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/BaichuanVideoStream-NTIGPHYJ.js +0 -7
- package/dist/chunk-GVWJGQPT.js.map +0 -1
- package/dist/chunk-OJQLZETO.js.map +0 -1
- /package/dist/{BaichuanVideoStream-NTIGPHYJ.js.map → BaichuanVideoStream-OCLOM452.js.map} +0 -0
- /package/dist/{DiagnosticsTools-7BIWJDZS.js.map → DiagnosticsTools-K4MF2VXZ.js.map} +0 -0
- /package/dist/{chunk-VOPEOB4H.js.map → chunk-XDVBNZGR.js.map} +0 -0
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
runAllDiagnosticsConsecutively,
|
|
31
31
|
runMultifocalDiagnosticsConsecutively,
|
|
32
32
|
xmlEscape
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-XDVBNZGR.js";
|
|
34
34
|
import {
|
|
35
35
|
BC_CLASS_FILE_DOWNLOAD,
|
|
36
36
|
BC_CLASS_LEGACY,
|
|
@@ -178,7 +178,7 @@ import {
|
|
|
178
178
|
splitAnnexBToNalPayloads2,
|
|
179
179
|
talkTraceLog,
|
|
180
180
|
traceLog
|
|
181
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-MZUSWKF3.js";
|
|
182
182
|
|
|
183
183
|
// src/protocol/framing.ts
|
|
184
184
|
function encodeHeader(h) {
|
|
@@ -619,6 +619,143 @@ function parseD2cHb(xml) {
|
|
|
619
619
|
return { cid: Number(cid), did: Number(did) };
|
|
620
620
|
}
|
|
621
621
|
|
|
622
|
+
// src/cloud/server-binding.ts
|
|
623
|
+
var REOLINK_API_V2_BASE = "https://apis.reolink.com/v2";
|
|
624
|
+
var POSITIVE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
625
|
+
var NEGATIVE_TTL_MS = 30 * 1e3;
|
|
626
|
+
var cache = /* @__PURE__ */ new Map();
|
|
627
|
+
function readCache(uid, now) {
|
|
628
|
+
const e = cache.get(uid);
|
|
629
|
+
if (!e) return void 0;
|
|
630
|
+
if (now >= e.expires) {
|
|
631
|
+
cache.delete(uid);
|
|
632
|
+
return void 0;
|
|
633
|
+
}
|
|
634
|
+
return e;
|
|
635
|
+
}
|
|
636
|
+
async function getServerBinding(uid, options = {}) {
|
|
637
|
+
if (!uid || typeof uid !== "string") return void 0;
|
|
638
|
+
const now = Date.now();
|
|
639
|
+
const cached = readCache(uid, now);
|
|
640
|
+
if (cached?.kind === "ok") return cached.response;
|
|
641
|
+
if (cached?.kind === "err") return void 0;
|
|
642
|
+
const language = options.language ?? "en";
|
|
643
|
+
const baseUrl = options.baseUrl ?? REOLINK_API_V2_BASE;
|
|
644
|
+
const timeoutMs = options.timeoutMs ?? 4e3;
|
|
645
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
646
|
+
const logger = options.logger;
|
|
647
|
+
if (typeof fetchImpl !== "function") {
|
|
648
|
+
logger?.debug?.(
|
|
649
|
+
`[server-binding] global fetch unavailable; skipping cloud lookup`
|
|
650
|
+
);
|
|
651
|
+
cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
|
|
652
|
+
return void 0;
|
|
653
|
+
}
|
|
654
|
+
const url = `${baseUrl}/devices/${encodeURIComponent(uid)}/server-binding?language=${encodeURIComponent(language)}`;
|
|
655
|
+
const controller = new AbortController();
|
|
656
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
657
|
+
try {
|
|
658
|
+
const res = await fetchImpl(url, {
|
|
659
|
+
method: "GET",
|
|
660
|
+
signal: controller.signal,
|
|
661
|
+
headers: { Accept: "application/json" }
|
|
662
|
+
});
|
|
663
|
+
if (!res.ok) {
|
|
664
|
+
logger?.debug?.(
|
|
665
|
+
`[server-binding] ${uid}: HTTP ${res.status} ${res.statusText}`
|
|
666
|
+
);
|
|
667
|
+
cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
|
|
668
|
+
return void 0;
|
|
669
|
+
}
|
|
670
|
+
const json = await res.json();
|
|
671
|
+
const parsed = parseServerBindingResponse(json);
|
|
672
|
+
if (!parsed) {
|
|
673
|
+
logger?.debug?.(
|
|
674
|
+
`[server-binding] ${uid}: response shape did not match expectations`
|
|
675
|
+
);
|
|
676
|
+
cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
|
|
677
|
+
return void 0;
|
|
678
|
+
}
|
|
679
|
+
cache.set(uid, {
|
|
680
|
+
kind: "ok",
|
|
681
|
+
response: parsed,
|
|
682
|
+
expires: now + POSITIVE_TTL_MS
|
|
683
|
+
});
|
|
684
|
+
const pick = parsed.availableZones.find(
|
|
685
|
+
(z) => z.status === "active" && z.services.p2p?.server
|
|
686
|
+
);
|
|
687
|
+
const hint = pick?.services.p2p?.server ?? parsed.availableZones[0]?.services.p2p?.server;
|
|
688
|
+
logger?.log?.(
|
|
689
|
+
`[server-binding] ${uid}: ${parsed.availableZones.length} zone(s)${hint ? `, p2p hint=${hint}` : ""}`
|
|
690
|
+
);
|
|
691
|
+
return parsed;
|
|
692
|
+
} catch (e) {
|
|
693
|
+
logger?.debug?.(
|
|
694
|
+
`[server-binding] ${uid}: ${e?.message ?? String(e)}`
|
|
695
|
+
);
|
|
696
|
+
cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
|
|
697
|
+
return void 0;
|
|
698
|
+
} finally {
|
|
699
|
+
clearTimeout(timer);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
function pickP2pHostFromBinding(response) {
|
|
703
|
+
if (!response) return void 0;
|
|
704
|
+
const zones = response.availableZones;
|
|
705
|
+
if (!zones || zones.length === 0) return void 0;
|
|
706
|
+
const active = zones.find(
|
|
707
|
+
(z) => z.status === "active" && z.services.p2p?.server
|
|
708
|
+
);
|
|
709
|
+
if (active?.services.p2p?.server) return active.services.p2p.server;
|
|
710
|
+
const def = zones.find(
|
|
711
|
+
(z) => z.status === "default" && z.services.p2p?.server
|
|
712
|
+
);
|
|
713
|
+
if (def?.services.p2p?.server) return def.services.p2p.server;
|
|
714
|
+
const any = zones.find((z) => z.services.p2p?.server);
|
|
715
|
+
return any?.services.p2p?.server;
|
|
716
|
+
}
|
|
717
|
+
function isString(v) {
|
|
718
|
+
return typeof v === "string";
|
|
719
|
+
}
|
|
720
|
+
function parseServerBindingResponse(raw) {
|
|
721
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
722
|
+
const rawZones = raw.availableZones;
|
|
723
|
+
if (!Array.isArray(rawZones)) return void 0;
|
|
724
|
+
const zones = [];
|
|
725
|
+
for (const r of rawZones) {
|
|
726
|
+
if (!r || typeof r !== "object") continue;
|
|
727
|
+
const rec = r;
|
|
728
|
+
const id = rec.id;
|
|
729
|
+
const name = rec.name;
|
|
730
|
+
const status = rec.status;
|
|
731
|
+
if (!isString(id) || !isString(name) || !isString(status)) continue;
|
|
732
|
+
const servicesRaw = rec.services;
|
|
733
|
+
const services = {};
|
|
734
|
+
if (servicesRaw && typeof servicesRaw === "object") {
|
|
735
|
+
const s = servicesRaw;
|
|
736
|
+
for (const key of ["p2p", "cloud", "roms_ota", "alarm_push"]) {
|
|
737
|
+
const v = s[key];
|
|
738
|
+
if (v && typeof v === "object") {
|
|
739
|
+
const server = v.server;
|
|
740
|
+
if (isString(server) && server.length > 0) {
|
|
741
|
+
services[key] = { server };
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
const locationsRaw = rec.locations;
|
|
747
|
+
const locations = Array.isArray(locationsRaw) && locationsRaw.every(isString) ? locationsRaw : void 0;
|
|
748
|
+
zones.push({
|
|
749
|
+
id,
|
|
750
|
+
name,
|
|
751
|
+
status,
|
|
752
|
+
services,
|
|
753
|
+
...locations ? { locations } : {}
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
return { availableZones: zones };
|
|
757
|
+
}
|
|
758
|
+
|
|
622
759
|
// src/bcudp/BcUdpStream.ts
|
|
623
760
|
var AckLatency = class {
|
|
624
761
|
currentValues = [];
|
|
@@ -700,6 +837,16 @@ var P2P_MAX_WAIT_MS = 15e3;
|
|
|
700
837
|
var P2P_RESEND_WAIT_MS = 500;
|
|
701
838
|
var BcUdpStream = class extends EventEmitter {
|
|
702
839
|
opts;
|
|
840
|
+
/**
|
|
841
|
+
* Optional info-level logger for diagnostic milestones — set via
|
|
842
|
+
* {@link BcUdpStream.setLogger} by `BaichuanClient` so the lib's
|
|
843
|
+
* standard logger sink sees BCUDP / P2P progress (DNS resolutions,
|
|
844
|
+
* outgoing UDP probes, timeouts with elapsed times) without the user
|
|
845
|
+
* having to opt into the per-packet `debug` event firehose. Kept
|
|
846
|
+
* separate from `emit('debug', ...)` because that channel is intended
|
|
847
|
+
* for the per-packet debug trace and is gated by debugOptions.
|
|
848
|
+
*/
|
|
849
|
+
discoveryLogger;
|
|
703
850
|
sock;
|
|
704
851
|
remote;
|
|
705
852
|
mtu;
|
|
@@ -743,6 +890,17 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
743
890
|
this.mtu = BCUDP_DEFAULT_MTU;
|
|
744
891
|
}
|
|
745
892
|
/** True if the underlying UDP socket is open and the remote peer is known. */
|
|
893
|
+
/**
|
|
894
|
+
* Attach an info-level logger for high-signal diagnostic milestones
|
|
895
|
+
* (DNS resolution, outgoing UDP probe sends, P2P UID lookup wins/losses,
|
|
896
|
+
* BCUDP local discovery timeouts). The lib's `BaichuanClient` calls
|
|
897
|
+
* this immediately after constructing the stream so consumers get
|
|
898
|
+
* actionable progress logs without enabling the per-packet debug trace.
|
|
899
|
+
* Safe to call repeatedly; only the most recent logger is used.
|
|
900
|
+
*/
|
|
901
|
+
setLogger(logger) {
|
|
902
|
+
this.discoveryLogger = logger;
|
|
903
|
+
}
|
|
746
904
|
isConnected() {
|
|
747
905
|
return !!this.sock && !!this.remote && this.cameraId != null;
|
|
748
906
|
}
|
|
@@ -860,20 +1018,60 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
860
1018
|
this.remote = { host: connected.rhost, port: connected.rport };
|
|
861
1019
|
}
|
|
862
1020
|
async p2pUidLookup(sock, uid) {
|
|
1021
|
+
const log = (msg) => this.discoveryLogger?.log?.(`[P2P] ${msg}`);
|
|
1022
|
+
const shortUid = uid.length > 7 ? `${uid.slice(0, 5)}\u2026${uid.slice(-2)}` : uid;
|
|
1023
|
+
const t0 = Date.now();
|
|
1024
|
+
const hostnamesToTry = [];
|
|
1025
|
+
const binding = await getServerBinding(uid, {
|
|
1026
|
+
...this.discoveryLogger ? { logger: this.discoveryLogger } : {}
|
|
1027
|
+
}).catch(() => void 0);
|
|
1028
|
+
const hintedHost = pickP2pHostFromBinding(binding);
|
|
1029
|
+
if (hintedHost) {
|
|
1030
|
+
hostnamesToTry.push(hintedHost);
|
|
1031
|
+
log(
|
|
1032
|
+
`UID=${shortUid} cloud server-binding \u2192 hint=${hintedHost} (will try first)`
|
|
1033
|
+
);
|
|
1034
|
+
} else {
|
|
1035
|
+
log(
|
|
1036
|
+
`UID=${shortUid} cloud server-binding \u2192 no hint (apis.reolink.com unreachable / no zone match) \u2192 sweeping ${P2P_RELAY_HOSTNAMES.length} fallback hostnames`
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
for (const host of P2P_RELAY_HOSTNAMES) {
|
|
1040
|
+
if (!hostnamesToTry.includes(host)) hostnamesToTry.push(host);
|
|
1041
|
+
}
|
|
863
1042
|
const resolved = [];
|
|
864
1043
|
const sinkholed = [];
|
|
865
|
-
for (const host of
|
|
1044
|
+
for (const host of hostnamesToTry) {
|
|
866
1045
|
try {
|
|
867
1046
|
const answers = await dns.lookup(host, { family: 4, all: true });
|
|
1047
|
+
let publicCount = 0;
|
|
1048
|
+
let sinkCount = 0;
|
|
868
1049
|
for (const a of answers) {
|
|
869
1050
|
if (!a.address) continue;
|
|
870
1051
|
if (isUnroutableForP2P(a.address)) {
|
|
871
1052
|
sinkholed.push({ host, ip: a.address });
|
|
1053
|
+
sinkCount++;
|
|
872
1054
|
continue;
|
|
873
1055
|
}
|
|
874
|
-
if (!resolved.includes(a.address))
|
|
1056
|
+
if (!resolved.includes(a.address)) {
|
|
1057
|
+
resolved.push(a.address);
|
|
1058
|
+
publicCount++;
|
|
1059
|
+
}
|
|
875
1060
|
}
|
|
876
|
-
|
|
1061
|
+
if (sinkCount > 0 && publicCount === 0) {
|
|
1062
|
+
log(
|
|
1063
|
+
`DNS ${host} \u2192 sinkhole (${sinkholed[sinkholed.length - 1]?.ip}) \u2014 DNS filter / /etc/hosts override`
|
|
1064
|
+
);
|
|
1065
|
+
} else if (publicCount > 0) {
|
|
1066
|
+
if (host === hintedHost) {
|
|
1067
|
+
log(`DNS ${host} \u2192 ${answers.find((a) => !isUnroutableForP2P(a.address))?.address} \u2713`);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
} catch (e) {
|
|
1071
|
+
log(`DNS ${host} \u2192 ENOTFOUND/timeout (${e?.code ?? "?"})`);
|
|
1072
|
+
}
|
|
1073
|
+
if (hintedHost && host === hintedHost && resolved.length > 0 && sinkholed.length === 0) {
|
|
1074
|
+
break;
|
|
877
1075
|
}
|
|
878
1076
|
}
|
|
879
1077
|
if (resolved.length === 0) {
|
|
@@ -887,11 +1085,22 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
887
1085
|
"P2P UID lookup failed: no p2p.reolink.com addresses resolved (DNS failure)"
|
|
888
1086
|
);
|
|
889
1087
|
}
|
|
1088
|
+
log(
|
|
1089
|
+
`Resolved ${resolved.length} P2P relay IP(s) (${resolved.slice(0, 3).join(", ")}${resolved.length > 3 ? "\u2026" : ""}). Sending C2M_Q probes (3s budget each, ${P2P_MAX_WAIT_MS}ms total)`
|
|
1090
|
+
);
|
|
890
1091
|
const start = Date.now();
|
|
891
1092
|
let lastErr;
|
|
1093
|
+
let attemptsMade = 0;
|
|
892
1094
|
for (const ip of resolved) {
|
|
893
1095
|
const remaining = P2P_MAX_WAIT_MS - (Date.now() - start);
|
|
894
|
-
if (remaining <= 0)
|
|
1096
|
+
if (remaining <= 0) {
|
|
1097
|
+
log(
|
|
1098
|
+
`Aborting after ${attemptsMade} attempt(s) \u2014 total budget ${P2P_MAX_WAIT_MS}ms exhausted`
|
|
1099
|
+
);
|
|
1100
|
+
break;
|
|
1101
|
+
}
|
|
1102
|
+
attemptsMade++;
|
|
1103
|
+
const probeStart = Date.now();
|
|
895
1104
|
try {
|
|
896
1105
|
const res = await this.p2pUidLookupOne(
|
|
897
1106
|
sock,
|
|
@@ -899,11 +1108,20 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
899
1108
|
{ host: ip, port: P2P_LOOKUP_PORT },
|
|
900
1109
|
Math.min(remaining, 3e3)
|
|
901
1110
|
);
|
|
1111
|
+
log(
|
|
1112
|
+
`${ip}:${P2P_LOOKUP_PORT} replied in ${Date.now() - probeStart}ms \u2713 (total ${Date.now() - t0}ms)`
|
|
1113
|
+
);
|
|
902
1114
|
return res;
|
|
903
1115
|
} catch (e) {
|
|
1116
|
+
const ms = Date.now() - probeStart;
|
|
1117
|
+
const msg = e?.message ?? String(e);
|
|
1118
|
+
log(`${ip}:${P2P_LOOKUP_PORT} no reply after ${ms}ms (${msg})`);
|
|
904
1119
|
lastErr = e instanceof Error ? e : new Error(String(e));
|
|
905
1120
|
}
|
|
906
1121
|
}
|
|
1122
|
+
log(
|
|
1123
|
+
`Exhausted all ${attemptsMade} relay candidate(s) after ${Date.now() - t0}ms \u2014 UID lookup failed`
|
|
1124
|
+
);
|
|
907
1125
|
throw lastErr ?? new Error("P2P UID lookup failed");
|
|
908
1126
|
}
|
|
909
1127
|
async p2pUidLookupOne(sock, uid, dest, timeoutMs) {
|
|
@@ -1242,13 +1460,23 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
1242
1460
|
const directHost = (this.opts.directHost ?? "").trim();
|
|
1243
1461
|
const localMode = opts?.localMode ?? "local-broadcast";
|
|
1244
1462
|
const directFirstWindowMs = localMode === "local-direct" && directHost ? 3e3 : 0;
|
|
1245
|
-
const discoveryTimeout =
|
|
1463
|
+
const discoveryTimeout = typeof this.opts.localDiscoveryTimeoutMs === "number" && this.opts.localDiscoveryTimeoutMs > 0 ? this.opts.localDiscoveryTimeoutMs : 15e3;
|
|
1246
1464
|
const retryInterval = 500;
|
|
1247
1465
|
const startMs = Date.now();
|
|
1248
1466
|
sock.setBroadcast(true);
|
|
1249
1467
|
const addr = sock.address();
|
|
1250
1468
|
const localPort = typeof addr === "string" ? 0 : addr.port;
|
|
1251
1469
|
const cid = Math.floor(Math.random() * 2147483647) | 0 || 82e3;
|
|
1470
|
+
const log = (msg) => this.discoveryLogger?.log?.(`[BCUDP] ${msg}`);
|
|
1471
|
+
const shortUid = this.opts.uid.length > 7 ? `${this.opts.uid.slice(0, 5)}\u2026${this.opts.uid.slice(-2)}` : this.opts.uid;
|
|
1472
|
+
log(
|
|
1473
|
+
`local discovery: mode=${localMode} uid=${shortUid} ports=[${ports.join(", ")}] broadcasts=[${broadcastHosts.join(", ")}]${directHost ? ` direct=${directHost}` : ""} localBindPort=${localPort} timeout=${discoveryTimeout}ms`
|
|
1474
|
+
);
|
|
1475
|
+
let bytesSent = 0;
|
|
1476
|
+
let pktsRecv = 0;
|
|
1477
|
+
sock.on("message", () => {
|
|
1478
|
+
pktsRecv++;
|
|
1479
|
+
});
|
|
1252
1480
|
const xml = buildC2dC({
|
|
1253
1481
|
uid: this.opts.uid,
|
|
1254
1482
|
clientPort: localPort,
|
|
@@ -1259,6 +1487,9 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
1259
1487
|
const timeout = setTimeout(() => {
|
|
1260
1488
|
if (retryTimer) clearInterval(retryTimer);
|
|
1261
1489
|
sock.off("message", onMsg);
|
|
1490
|
+
log(
|
|
1491
|
+
`local discovery timeout after ${discoveryTimeout}ms \u2014 sent=${bytesSent}B replies=${pktsRecv} (camera likely sleeping / off-LAN / firewall dropping replies)`
|
|
1492
|
+
);
|
|
1262
1493
|
reject(
|
|
1263
1494
|
new Error(
|
|
1264
1495
|
`BCUDP discovery timeout after ${discoveryTimeout}ms (camera may be sleeping or unreachable)`
|
|
@@ -1452,6 +1683,7 @@ var BcUdpStream = class extends EventEmitter {
|
|
|
1452
1683
|
for (const port of ports) {
|
|
1453
1684
|
try {
|
|
1454
1685
|
sock.send(packet, port, host);
|
|
1686
|
+
bytesSent += packet.length;
|
|
1455
1687
|
retryCount++;
|
|
1456
1688
|
this.emit("debug", "discovery_send", { retryCount, host, port });
|
|
1457
1689
|
} catch {
|
|
@@ -2988,6 +3220,7 @@ var BaichuanClient = class _BaichuanClient extends EventEmitter2 {
|
|
|
2988
3220
|
sock.on("debug", (event, data) => {
|
|
2989
3221
|
this.logDebug(`udp_${event}`, data);
|
|
2990
3222
|
});
|
|
3223
|
+
sock.setLogger(this.logger);
|
|
2991
3224
|
await sock.connect();
|
|
2992
3225
|
const shortUid = this.opts.uid ? this.opts.uid.substring(0, 5) : "";
|
|
2993
3226
|
const udpDiscoveryMethod = this.opts.udpDiscoveryMethod ?? "local-direct";
|
|
@@ -13504,7 +13737,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
13504
13737
|
return;
|
|
13505
13738
|
}
|
|
13506
13739
|
entry.startInFlight = (async () => {
|
|
13507
|
-
const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-
|
|
13740
|
+
const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-OCLOM452.js");
|
|
13508
13741
|
const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
|
|
13509
13742
|
const dedicated = await this.createDedicatedSession(sessionKey);
|
|
13510
13743
|
const stream = new BaichuanVideoStream2({
|
|
@@ -20234,7 +20467,7 @@ ${xml}`
|
|
|
20234
20467
|
* @returns Test results for all stream types and profiles
|
|
20235
20468
|
*/
|
|
20236
20469
|
async testChannelStreams(channel, logger) {
|
|
20237
|
-
const { testChannelStreams } = await import("./DiagnosticsTools-
|
|
20470
|
+
const { testChannelStreams } = await import("./DiagnosticsTools-K4MF2VXZ.js");
|
|
20238
20471
|
return await testChannelStreams({
|
|
20239
20472
|
api: this,
|
|
20240
20473
|
channel: this.normalizeChannel(channel),
|
|
@@ -20250,7 +20483,7 @@ ${xml}`
|
|
|
20250
20483
|
* @returns Complete diagnostics for all channels and streams
|
|
20251
20484
|
*/
|
|
20252
20485
|
async collectMultifocalDiagnostics(logger) {
|
|
20253
|
-
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-
|
|
20486
|
+
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-K4MF2VXZ.js");
|
|
20254
20487
|
return await collectMultifocalDiagnostics({
|
|
20255
20488
|
api: this,
|
|
20256
20489
|
logger
|
|
@@ -24305,7 +24538,11 @@ async function discoverUidForHost(host, logger) {
|
|
|
24305
24538
|
function isTcpFailureThatShouldFallbackToUdp(e) {
|
|
24306
24539
|
const message = e?.message || e?.toString?.() || "";
|
|
24307
24540
|
if (typeof message !== "string") return false;
|
|
24308
|
-
return message.includes("ECONNREFUSED") || message.includes("ETIMEDOUT") || message.includes("
|
|
24541
|
+
return message.includes("ECONNREFUSED") || message.includes("ETIMEDOUT") || message.includes("EHOSTDOWN") || message.includes("EHOSTUNREACH") || message.includes("ENETUNREACH") || message.includes("ENETDOWN") || message.includes("socket hang up") || message.includes("TCP connection timeout") || // Autodetect's own hard deadline on the TCP login attempt — see
|
|
24542
|
+
// `withTcpDeadline` in `autoDetectDeviceType`. Without this entry the
|
|
24543
|
+
// catch block would rethrow the deadline error instead of awaiting
|
|
24544
|
+
// the speculative UDP race.
|
|
24545
|
+
message.includes("TCP login deadline exceeded") || message.includes("Baichuan socket closed") || message.includes("timeout waiting for nonce") || message.includes("expected encryption info") || message.includes("ECONNRESET") || message.includes("EPIPE");
|
|
24309
24546
|
}
|
|
24310
24547
|
async function pingHost(host, timeoutMs = 3e3) {
|
|
24311
24548
|
if (!host || typeof host !== "string") return false;
|
|
@@ -24453,6 +24690,7 @@ function attachErrorHandler(api, transport, inputs) {
|
|
|
24453
24690
|
}
|
|
24454
24691
|
async function autoDetectDeviceType(inputs) {
|
|
24455
24692
|
const { host, uid, logger } = inputs;
|
|
24693
|
+
const autodetectStartedAt = Date.now();
|
|
24456
24694
|
const mode = inputs.mode ?? "auto";
|
|
24457
24695
|
const maxRetriesRaw = inputs.maxRetries;
|
|
24458
24696
|
const maxRetries = Math.max(
|
|
@@ -24469,9 +24707,31 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24469
24707
|
const sleepMs2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
24470
24708
|
const shouldRetryTcp = (e) => {
|
|
24471
24709
|
const msg = fmtErr(e);
|
|
24472
|
-
if (msg.includes("ECONNREFUSED"))
|
|
24710
|
+
if (msg.includes("ECONNREFUSED") || msg.includes("EHOSTDOWN") || msg.includes("EHOSTUNREACH") || msg.includes("ENETUNREACH") || msg.includes("ENETDOWN")) {
|
|
24711
|
+
return false;
|
|
24712
|
+
}
|
|
24473
24713
|
return isTcpFailureThatShouldFallbackToUdp(e) || msg.includes("timeout waiting for nonce") || msg.includes("expected encryption info") || msg.includes("Baichuan socket closed") || msg.includes("ECONNRESET") || msg.includes("EPIPE");
|
|
24474
24714
|
};
|
|
24715
|
+
const tcpDeadlineMs = typeof inputs.tcpConnectTimeoutMs === "number" && Number.isFinite(inputs.tcpConnectTimeoutMs) && inputs.tcpConnectTimeoutMs > 0 ? inputs.tcpConnectTimeoutMs : 8e3;
|
|
24716
|
+
const withTcpDeadline = async (op) => {
|
|
24717
|
+
let timer;
|
|
24718
|
+
const deadline = new Promise((_, reject) => {
|
|
24719
|
+
timer = setTimeout(
|
|
24720
|
+
() => reject(
|
|
24721
|
+
new Error(
|
|
24722
|
+
`TCP login deadline exceeded (${tcpDeadlineMs}ms) \u2014 host unreachable`
|
|
24723
|
+
)
|
|
24724
|
+
),
|
|
24725
|
+
tcpDeadlineMs
|
|
24726
|
+
);
|
|
24727
|
+
timer.unref?.();
|
|
24728
|
+
});
|
|
24729
|
+
try {
|
|
24730
|
+
return await Promise.race([op, deadline]);
|
|
24731
|
+
} finally {
|
|
24732
|
+
if (timer) clearTimeout(timer);
|
|
24733
|
+
}
|
|
24734
|
+
};
|
|
24475
24735
|
const shouldRetryUdp = (e) => {
|
|
24476
24736
|
const msg = fmtErr(e);
|
|
24477
24737
|
return msg.includes("Not running") || msg.includes("Baichuan UDP stream closed") || msg.includes("Baichuan socket closed") || msg.includes("ETIMEDOUT") || msg.toLowerCase().includes("timeout");
|
|
@@ -24624,6 +24884,127 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24624
24884
|
"Forced UDP autodetect failed for all methods."
|
|
24625
24885
|
);
|
|
24626
24886
|
}
|
|
24887
|
+
const detectOverUdpApi = async (udpApi, udpDiscoveryMethod, resolvedUid) => {
|
|
24888
|
+
const [deviceInfo, capabilities, hostNetworkInfo] = await Promise.all([
|
|
24889
|
+
udpApi.getInfo(),
|
|
24890
|
+
udpApi.getDeviceCapabilities(),
|
|
24891
|
+
udpApi.getNetworkInfo(void 0, { timeoutMs: 1200 }).catch(() => void 0)
|
|
24892
|
+
]);
|
|
24893
|
+
const channelNum = capabilities?.support?.channelNum ?? 1;
|
|
24894
|
+
const model = deviceInfo.type?.trim();
|
|
24895
|
+
const normalizedModel = model ? model.trim() : void 0;
|
|
24896
|
+
const isMultifocalByModel = normalizedModel ? isDualLenseModel(normalizedModel) : false;
|
|
24897
|
+
const channelNumValue = typeof channelNum === "string" ? Number.parseInt(channelNum, 10) : channelNum;
|
|
24898
|
+
const hasDualLensChannelCount = (channelNumValue === 2 || channelNumValue === 3) && Number.isFinite(channelNumValue);
|
|
24899
|
+
const isMultifocal = isMultifocalByModel || hasDualLensChannelCount;
|
|
24900
|
+
const hasBattery = capabilities?.capabilities?.hasBattery === true;
|
|
24901
|
+
udpApi.setIdleDisconnect(hasBattery);
|
|
24902
|
+
if (isMultifocal) {
|
|
24903
|
+
const detectionMethod = isMultifocalByModel ? "model match" : "channelNum fallback";
|
|
24904
|
+
logger?.log?.(
|
|
24905
|
+
`[AutoDetect] UDP (${udpDiscoveryMethod}) connection successful. Detected multi-focal device (${detectionMethod}: model=${normalizedModel ?? "unknown"}, channelNum=${channelNum}, hasBattery=${hasBattery}).`
|
|
24906
|
+
);
|
|
24907
|
+
return {
|
|
24908
|
+
type: "multifocal",
|
|
24909
|
+
transport: "udp",
|
|
24910
|
+
uid: resolvedUid,
|
|
24911
|
+
udpDiscoveryMethod,
|
|
24912
|
+
deviceInfo,
|
|
24913
|
+
...hostNetworkInfo ? { hostNetworkInfo } : {},
|
|
24914
|
+
channelNum,
|
|
24915
|
+
hasBattery,
|
|
24916
|
+
api: udpApi
|
|
24917
|
+
};
|
|
24918
|
+
}
|
|
24919
|
+
const deviceType = hasBattery ? "battery-cam" : "udp-camera";
|
|
24920
|
+
logger?.log?.(
|
|
24921
|
+
`[AutoDetect] UDP (${udpDiscoveryMethod}) connection successful. Detected ${deviceType} (hasBattery=${hasBattery}, model=${normalizedModel ?? "unknown"}).`
|
|
24922
|
+
);
|
|
24923
|
+
return {
|
|
24924
|
+
type: deviceType,
|
|
24925
|
+
transport: "udp",
|
|
24926
|
+
uid: resolvedUid,
|
|
24927
|
+
udpDiscoveryMethod,
|
|
24928
|
+
deviceInfo,
|
|
24929
|
+
...hostNetworkInfo ? { hostNetworkInfo } : {},
|
|
24930
|
+
channelNum: 1,
|
|
24931
|
+
hasBattery,
|
|
24932
|
+
api: udpApi
|
|
24933
|
+
};
|
|
24934
|
+
};
|
|
24935
|
+
const udpRaceAbort = new AbortController();
|
|
24936
|
+
const speculativeUdpRace = mode === "auto" ? (async () => {
|
|
24937
|
+
const resolvedUid = await speculativeUidPromise;
|
|
24938
|
+
const viableMethods = selectViableUdpMethods(Boolean(resolvedUid));
|
|
24939
|
+
return await runUdpMethodsParallel(
|
|
24940
|
+
viableMethods,
|
|
24941
|
+
async (m, isInnerAborted) => {
|
|
24942
|
+
const isAborted = () => udpRaceAbort.signal.aborted || isInnerAborted();
|
|
24943
|
+
if (isAborted()) {
|
|
24944
|
+
throw new Error(
|
|
24945
|
+
`UDP(${m}) speculative race aborted before start`
|
|
24946
|
+
);
|
|
24947
|
+
}
|
|
24948
|
+
logger?.log?.(
|
|
24949
|
+
`[AutoDetect] (race) Trying UDP discovery method: ${m}...`
|
|
24950
|
+
);
|
|
24951
|
+
const udpApi = await withRetries(
|
|
24952
|
+
`UDP(${m})`,
|
|
24953
|
+
maxRetries,
|
|
24954
|
+
async (attempt) => {
|
|
24955
|
+
const apiInputs = {
|
|
24956
|
+
...inputs,
|
|
24957
|
+
udpDiscoveryMethod: m
|
|
24958
|
+
};
|
|
24959
|
+
if (resolvedUid) apiInputs.uid = resolvedUid;
|
|
24960
|
+
const api = createBaichuanApi(apiInputs, "udp");
|
|
24961
|
+
try {
|
|
24962
|
+
await api.login();
|
|
24963
|
+
return api;
|
|
24964
|
+
} catch (e) {
|
|
24965
|
+
try {
|
|
24966
|
+
await api.close({
|
|
24967
|
+
reason: `autodetect:udp_failed:${m}:attempt_${attempt}`
|
|
24968
|
+
});
|
|
24969
|
+
} catch {
|
|
24970
|
+
}
|
|
24971
|
+
throw e;
|
|
24972
|
+
}
|
|
24973
|
+
},
|
|
24974
|
+
shouldRetryUdp,
|
|
24975
|
+
isAborted
|
|
24976
|
+
);
|
|
24977
|
+
if (isAborted()) {
|
|
24978
|
+
try {
|
|
24979
|
+
await udpApi.close({
|
|
24980
|
+
reason: "autodetect:udp_aborted_after_tcp_won"
|
|
24981
|
+
});
|
|
24982
|
+
} catch {
|
|
24983
|
+
}
|
|
24984
|
+
throw new Error(
|
|
24985
|
+
`UDP(${m}) speculative race aborted after login`
|
|
24986
|
+
);
|
|
24987
|
+
}
|
|
24988
|
+
return detectOverUdpApi(udpApi, m, resolvedUid ?? "");
|
|
24989
|
+
},
|
|
24990
|
+
"Speculative UDP race failed for all methods."
|
|
24991
|
+
);
|
|
24992
|
+
})() : void 0;
|
|
24993
|
+
speculativeUdpRace?.then(
|
|
24994
|
+
(udpResult) => {
|
|
24995
|
+
if (udpRaceAbort.signal.aborted && udpResult?.api) {
|
|
24996
|
+
udpResult.api.close({ reason: "autodetect:tcp_won_race" }).catch(() => void 0);
|
|
24997
|
+
}
|
|
24998
|
+
},
|
|
24999
|
+
() => void 0
|
|
25000
|
+
);
|
|
25001
|
+
const _tcpWin = (result) => {
|
|
25002
|
+
udpRaceAbort.abort();
|
|
25003
|
+
logger?.log?.(
|
|
25004
|
+
`[AutoDetect] DONE in ${Date.now() - autodetectStartedAt}ms via TCP \u2014 type=${result.type} model=${result.deviceInfo?.type ?? "?"} channels=${result.channelNum}`
|
|
25005
|
+
);
|
|
25006
|
+
return result;
|
|
25007
|
+
};
|
|
24627
25008
|
let tcpApi;
|
|
24628
25009
|
try {
|
|
24629
25010
|
logger?.log?.(`[AutoDetect] Trying TCP connection to ${host}...`);
|
|
@@ -24633,7 +25014,7 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24633
25014
|
async (attempt) => {
|
|
24634
25015
|
const api2 = createBaichuanApi(inputs, "tcp");
|
|
24635
25016
|
try {
|
|
24636
|
-
await api2.login();
|
|
25017
|
+
await withTcpDeadline(api2.login());
|
|
24637
25018
|
return api2;
|
|
24638
25019
|
} catch (e) {
|
|
24639
25020
|
try {
|
|
@@ -24745,7 +25126,7 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24745
25126
|
logger?.log?.(
|
|
24746
25127
|
`[AutoDetect] Detected multi-focal device (${detectionMethod}: model=${normalizedModel ?? "unknown"}, channelNum=${channelNum})`
|
|
24747
25128
|
);
|
|
24748
|
-
return {
|
|
25129
|
+
return _tcpWin({
|
|
24749
25130
|
type: "multifocal",
|
|
24750
25131
|
transport: "tcp",
|
|
24751
25132
|
uid: effectiveUid || uid || "",
|
|
@@ -24753,13 +25134,13 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24753
25134
|
// ...(hostNetworkInfo ? { hostNetworkInfo } : {}),
|
|
24754
25135
|
channelNum: effectiveChannelNum,
|
|
24755
25136
|
api
|
|
24756
|
-
};
|
|
25137
|
+
});
|
|
24757
25138
|
}
|
|
24758
25139
|
if (effectiveChannelNum > 1) {
|
|
24759
25140
|
logger?.log?.(
|
|
24760
25141
|
`[AutoDetect] Detected NVR (${effectiveChannelNum} channels)`
|
|
24761
25142
|
);
|
|
24762
|
-
return {
|
|
25143
|
+
return _tcpWin({
|
|
24763
25144
|
type: "nvr",
|
|
24764
25145
|
transport: "tcp",
|
|
24765
25146
|
uid: effectiveUid || uid || "",
|
|
@@ -24767,10 +25148,10 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24767
25148
|
// ...(hostNetworkInfo ? { hostNetworkInfo } : {}),
|
|
24768
25149
|
channelNum: effectiveChannelNum,
|
|
24769
25150
|
api
|
|
24770
|
-
};
|
|
25151
|
+
});
|
|
24771
25152
|
}
|
|
24772
25153
|
logger?.log?.(`[AutoDetect] Detected regular camera (single channel)`);
|
|
24773
|
-
return {
|
|
25154
|
+
return _tcpWin({
|
|
24774
25155
|
type: "camera",
|
|
24775
25156
|
transport: "tcp",
|
|
24776
25157
|
uid: effectiveUid || uid || "",
|
|
@@ -24778,7 +25159,7 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24778
25159
|
// ...(hostNetworkInfo ? { hostNetworkInfo } : {}),
|
|
24779
25160
|
channelNum: 1,
|
|
24780
25161
|
api
|
|
24781
|
-
};
|
|
25162
|
+
});
|
|
24782
25163
|
} catch (tcpError) {
|
|
24783
25164
|
if (mode === "tcp") {
|
|
24784
25165
|
throw tcpError;
|
|
@@ -24793,100 +25174,20 @@ async function autoDetectDeviceType(inputs) {
|
|
|
24793
25174
|
throw tcpError;
|
|
24794
25175
|
}
|
|
24795
25176
|
logger?.log?.(`[AutoDetect] TCP failed, trying UDP...`);
|
|
24796
|
-
|
|
24797
|
-
|
|
24798
|
-
|
|
24799
|
-
`[AutoDetect] UID discovery failed; only local-direct can run without a UID. If the camera is sleeping or on a different subnet, supply its UID to enable BCUDP P2P fallback (remote/relay/map) which can wake it via Reolink's servers.`
|
|
24800
|
-
);
|
|
24801
|
-
} else if (effectiveUid === void 0) {
|
|
24802
|
-
logger?.log?.(
|
|
24803
|
-
`[AutoDetect] UID resolved via concurrent broadcast discovery: ${normalizedUid}`
|
|
25177
|
+
if (!speculativeUdpRace) {
|
|
25178
|
+
throw new Error(
|
|
25179
|
+
`AutoDetect internal: speculative UDP race missing in mode=${mode}`
|
|
24804
25180
|
);
|
|
24805
25181
|
}
|
|
24806
25182
|
try {
|
|
24807
|
-
const
|
|
24808
|
-
|
|
24809
|
-
|
|
24810
|
-
udpApi.getDeviceCapabilities(),
|
|
24811
|
-
udpApi.getNetworkInfo(void 0, { timeoutMs: 1200 }).catch(() => void 0)
|
|
24812
|
-
]);
|
|
24813
|
-
const channelNum = capabilities?.support?.channelNum ?? 1;
|
|
24814
|
-
const model = deviceInfo.type?.trim();
|
|
24815
|
-
const normalizedModel = model ? model.trim() : void 0;
|
|
24816
|
-
const isMultifocalByModel = normalizedModel ? isDualLenseModel(normalizedModel) : false;
|
|
24817
|
-
const channelNumValue = typeof channelNum === "string" ? Number.parseInt(channelNum, 10) : channelNum;
|
|
24818
|
-
const hasDualLensChannelCount = (channelNumValue === 2 || channelNumValue === 3) && Number.isFinite(channelNumValue);
|
|
24819
|
-
const isMultifocal = isMultifocalByModel || hasDualLensChannelCount;
|
|
24820
|
-
const hasBattery = capabilities?.capabilities?.hasBattery === true;
|
|
24821
|
-
udpApi.setIdleDisconnect(hasBattery);
|
|
24822
|
-
if (isMultifocal) {
|
|
24823
|
-
const detectionMethod = isMultifocalByModel ? "model match" : "channelNum fallback";
|
|
24824
|
-
logger?.log?.(
|
|
24825
|
-
`[AutoDetect] UDP (${udpDiscoveryMethod}) connection successful. Detected multi-focal device (${detectionMethod}: model=${normalizedModel ?? "unknown"}, channelNum=${channelNum}, hasBattery=${hasBattery}).`
|
|
24826
|
-
);
|
|
24827
|
-
return {
|
|
24828
|
-
type: "multifocal",
|
|
24829
|
-
transport: "udp",
|
|
24830
|
-
uid: normalizedUid ?? "",
|
|
24831
|
-
udpDiscoveryMethod,
|
|
24832
|
-
deviceInfo,
|
|
24833
|
-
...hostNetworkInfo ? { hostNetworkInfo } : {},
|
|
24834
|
-
channelNum,
|
|
24835
|
-
hasBattery,
|
|
24836
|
-
api: udpApi
|
|
24837
|
-
};
|
|
24838
|
-
}
|
|
24839
|
-
const deviceType = hasBattery ? "battery-cam" : "udp-camera";
|
|
24840
|
-
logger?.log?.(
|
|
24841
|
-
`[AutoDetect] UDP (${udpDiscoveryMethod}) connection successful. Detected ${deviceType} (hasBattery=${hasBattery}, model=${normalizedModel ?? "unknown"}).`
|
|
24842
|
-
);
|
|
24843
|
-
return {
|
|
24844
|
-
type: deviceType,
|
|
24845
|
-
transport: "udp",
|
|
24846
|
-
uid: normalizedUid ?? "",
|
|
24847
|
-
udpDiscoveryMethod,
|
|
24848
|
-
deviceInfo,
|
|
24849
|
-
...hostNetworkInfo ? { hostNetworkInfo } : {},
|
|
24850
|
-
channelNum: 1,
|
|
24851
|
-
hasBattery,
|
|
24852
|
-
api: udpApi
|
|
24853
|
-
};
|
|
24854
|
-
};
|
|
24855
|
-
const viableMethods = selectViableUdpMethods(Boolean(normalizedUid));
|
|
24856
|
-
return await runUdpMethodsParallel(
|
|
24857
|
-
viableMethods,
|
|
24858
|
-
async (m, isAborted) => {
|
|
24859
|
-
logger?.log?.(`[AutoDetect] Trying UDP discovery method: ${m}...`);
|
|
24860
|
-
const udpApi = await withRetries(
|
|
24861
|
-
`UDP(${m})`,
|
|
24862
|
-
maxRetries,
|
|
24863
|
-
async (attempt) => {
|
|
24864
|
-
const apiInputs = { ...inputs, udpDiscoveryMethod: m };
|
|
24865
|
-
if (normalizedUid) apiInputs.uid = normalizedUid;
|
|
24866
|
-
const api = createBaichuanApi(apiInputs, "udp");
|
|
24867
|
-
try {
|
|
24868
|
-
await api.login();
|
|
24869
|
-
return api;
|
|
24870
|
-
} catch (e) {
|
|
24871
|
-
try {
|
|
24872
|
-
await api.close({
|
|
24873
|
-
reason: `autodetect:udp_failed:${m}:attempt_${attempt}`
|
|
24874
|
-
});
|
|
24875
|
-
} catch {
|
|
24876
|
-
}
|
|
24877
|
-
throw e;
|
|
24878
|
-
}
|
|
24879
|
-
},
|
|
24880
|
-
shouldRetryUdp,
|
|
24881
|
-
isAborted
|
|
24882
|
-
);
|
|
24883
|
-
return detectOverUdpApi(udpApi, m);
|
|
24884
|
-
},
|
|
24885
|
-
"UDP discovery failed for all methods."
|
|
25183
|
+
const udpResult = await speculativeUdpRace;
|
|
25184
|
+
logger?.log?.(
|
|
25185
|
+
`[AutoDetect] DONE in ${Date.now() - autodetectStartedAt}ms via UDP \u2014 type=${udpResult.type} method=${udpResult.udpDiscoveryMethod ?? "n/a"} model=${udpResult.deviceInfo?.type ?? "?"} channels=${udpResult.channelNum}`
|
|
24886
25186
|
);
|
|
25187
|
+
return udpResult;
|
|
24887
25188
|
} catch (udpError) {
|
|
24888
25189
|
logger?.log?.(
|
|
24889
|
-
`[AutoDetect]
|
|
25190
|
+
`[AutoDetect] FAILED after ${Date.now() - autodetectStartedAt}ms \u2014 neither TCP nor UDP could reach the camera. TCP: ${tcpError?.message ?? tcpError}. UDP: ${udpError?.message ?? udpError}`
|
|
24890
25191
|
);
|
|
24891
25192
|
throw new Error(
|
|
24892
25193
|
`Failed to connect via both TCP and UDP. TCP: ${tcpError?.message || tcpError}, UDP: ${udpError?.message || udpError}`
|
|
@@ -24967,4 +25268,4 @@ export {
|
|
|
24967
25268
|
tcpReachabilityProbe,
|
|
24968
25269
|
autoDetectDeviceType
|
|
24969
25270
|
};
|
|
24970
|
-
//# sourceMappingURL=chunk-
|
|
25271
|
+
//# sourceMappingURL=chunk-7HSTETZR.js.map
|