@apocaliss92/nodelink-js 0.4.15 → 0.4.17
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-BQOWJ23L.js → DiagnosticsTools-HO3VI6D5.js} +2 -2
- package/dist/{chunk-6KYLA4YI.js → chunk-EF6BCSCZ.js} +158 -95
- package/dist/chunk-EF6BCSCZ.js.map +1 -0
- package/dist/{chunk-2JNXKT3C.js → chunk-S2UTGNFN.js} +83 -4
- package/dist/chunk-S2UTGNFN.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +236 -94
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +2 -2
- package/dist/index.cjs +236 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -12
- package/dist/index.d.ts +29 -12
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-2JNXKT3C.js.map +0 -1
- package/dist/chunk-6KYLA4YI.js.map +0 -1
- /package/dist/{DiagnosticsTools-BQOWJ23L.js.map → DiagnosticsTools-HO3VI6D5.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
sampleStreams,
|
|
13
13
|
sanitizeFixtureData,
|
|
14
14
|
testChannelStreams
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-S2UTGNFN.js";
|
|
16
16
|
import "./chunk-C57QV7IL.js";
|
|
17
17
|
export {
|
|
18
18
|
captureModelFixtures,
|
|
@@ -29,4 +29,4 @@ export {
|
|
|
29
29
|
sanitizeFixtureData,
|
|
30
30
|
testChannelStreams
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=DiagnosticsTools-
|
|
32
|
+
//# sourceMappingURL=DiagnosticsTools-HO3VI6D5.js.map
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
runAllDiagnosticsConsecutively,
|
|
31
31
|
runMultifocalDiagnosticsConsecutively,
|
|
32
32
|
xmlEscape
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-S2UTGNFN.js";
|
|
34
34
|
import {
|
|
35
35
|
BC_CLASS_FILE_DOWNLOAD,
|
|
36
36
|
BC_CLASS_LEGACY,
|
|
@@ -10919,7 +10919,15 @@ var applyFloodlightSettingsToXml = (xml, settings) => {
|
|
|
10919
10919
|
// src/reolink/baichuan/ReolinkBaichuanApi.ts
|
|
10920
10920
|
var DUAL_LENS_DUAL_MOTION_MODELS = /* @__PURE__ */ new Set([
|
|
10921
10921
|
"Reolink Duo PoE",
|
|
10922
|
-
"Reolink Duo WiFi"
|
|
10922
|
+
"Reolink Duo WiFi",
|
|
10923
|
+
// Duo 2 family
|
|
10924
|
+
"Reolink Duo 2 PoE",
|
|
10925
|
+
"Reolink Duo 2 WiFi",
|
|
10926
|
+
// Duo 3 family — physically dual-sensor, marketed as a stitched 16MP feed
|
|
10927
|
+
// (the firmware exposes a single logical channel, so callers should still
|
|
10928
|
+
// check `getDualLensChannelInfo` for the actual channel topology).
|
|
10929
|
+
"Reolink Duo 3 PoE",
|
|
10930
|
+
"Reolink Duo 3 WiFi"
|
|
10923
10931
|
]);
|
|
10924
10932
|
var DUAL_LENS_SINGLE_MOTION_MODELS = /* @__PURE__ */ new Set([
|
|
10925
10933
|
"Reolink TrackMix",
|
|
@@ -10934,7 +10942,10 @@ var DUAL_LENS_MODELS = /* @__PURE__ */ new Set([
|
|
|
10934
10942
|
]);
|
|
10935
10943
|
var isDualLenseModel = (model) => {
|
|
10936
10944
|
const lower = model.toLowerCase();
|
|
10937
|
-
|
|
10945
|
+
if (Array.from(DUAL_LENS_MODELS).some((m) => m.toLowerCase() === lower)) {
|
|
10946
|
+
return true;
|
|
10947
|
+
}
|
|
10948
|
+
return lower.includes("trackmix") || lower.includes("trackflex") || /\bduo\b/.test(lower);
|
|
10938
10949
|
};
|
|
10939
10950
|
var NVR_HUB_EXACT_TYPES = ["NVR", "WIFI_NVR", "HOMEHUB"];
|
|
10940
10951
|
var NVR_HUB_MODEL_PATTERNS = [
|
|
@@ -11285,14 +11296,15 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
11285
11296
|
// _registerVideoStreamForDetection (called from BaichuanVideoStream.start).
|
|
11286
11297
|
detectionEventListeners = /* @__PURE__ */ new Set();
|
|
11287
11298
|
detectionEventStreamHooks = /* @__PURE__ */ new Map();
|
|
11288
|
-
// Auto-managed
|
|
11289
|
-
//
|
|
11290
|
-
//
|
|
11291
|
-
//
|
|
11292
|
-
//
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11299
|
+
// Auto-managed substreams for `onObjectDetections` listeners. One entry per
|
|
11300
|
+
// `(channel, profile)` tuple — required for NVR/Hub setups where AI boxes
|
|
11301
|
+
// live on a specific channel, and for callers that need detections off a
|
|
11302
|
+
// profile other than the default `sub`. The substream is opened on the first
|
|
11303
|
+
// listener of a tuple and torn down when the last one for that tuple leaves.
|
|
11304
|
+
objectDetectionSubs = /* @__PURE__ */ new Map();
|
|
11305
|
+
// Single bridge installed into `detectionEventListeners` while at least one
|
|
11306
|
+
// object-detection subscription is active. It routes events to the correct
|
|
11307
|
+
// tuple's listener set based on `event.channel` / `event.profile`.
|
|
11296
11308
|
objectDetectionInternalListener;
|
|
11297
11309
|
simpleEventSubscribeInFlight;
|
|
11298
11310
|
simpleEventUnsubscribeInFlight;
|
|
@@ -12760,87 +12772,129 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
12760
12772
|
* Subscribe to AI object detections (people / vehicle / animal / face boxes
|
|
12761
12773
|
* with class label and confidence) without managing a video stream yourself.
|
|
12762
12774
|
*
|
|
12763
|
-
* Mirrors {@link onSimpleEvent} end-to-end: the
|
|
12764
|
-
*
|
|
12765
|
-
*
|
|
12766
|
-
*
|
|
12767
|
-
*
|
|
12775
|
+
* Mirrors {@link onSimpleEvent} end-to-end: on the first listener for a given
|
|
12776
|
+
* `(channel, profile)` tuple the API ensures the corresponding video stream
|
|
12777
|
+
* is running (the pool socket may already be shared with a regular consumer),
|
|
12778
|
+
* forwards every box-bearing `additionalHeader` to your callback, and tears
|
|
12779
|
+
* the stream down when the last listener for that tuple unsubscribes.
|
|
12780
|
+
*
|
|
12781
|
+
* Defaults — `channel: 0`, `profile: "sub"` — match a single-lens standalone
|
|
12782
|
+
* camera. **For NVR/Hub child cameras you must pass the channel explicitly**,
|
|
12783
|
+
* otherwise the substream opens on channel 0 and never sees the AI boxes for
|
|
12784
|
+
* the other channels. The `sub` profile is recommended (lighter bandwidth)
|
|
12785
|
+
* but `main` / `ext` are accepted if you specifically need detections off a
|
|
12786
|
+
* different feed.
|
|
12768
12787
|
*
|
|
12769
12788
|
* Each event carries normalized `[0, 1]` box coordinates, a class label, and
|
|
12770
12789
|
* a confidence score — render-ready without further conversion.
|
|
12771
12790
|
*/
|
|
12772
|
-
async onObjectDetections(callback) {
|
|
12773
|
-
|
|
12791
|
+
async onObjectDetections(callback, options) {
|
|
12792
|
+
const channel = options?.channel ?? 0;
|
|
12793
|
+
const profile = options?.profile ?? "sub";
|
|
12794
|
+
const key = this.objectDetectionKey(channel, profile);
|
|
12795
|
+
let entry = this.objectDetectionSubs.get(key);
|
|
12796
|
+
if (!entry) {
|
|
12797
|
+
entry = { channel, profile, listeners: /* @__PURE__ */ new Set() };
|
|
12798
|
+
this.objectDetectionSubs.set(key, entry);
|
|
12799
|
+
}
|
|
12800
|
+
entry.listeners.add(callback);
|
|
12774
12801
|
this.logger.debug?.(
|
|
12775
|
-
`[ReolinkBaichuanApi] onObjectDetections: registering listener (total=${
|
|
12802
|
+
`[ReolinkBaichuanApi] onObjectDetections: registering listener for ch${channel}/${profile} (total=${entry.listeners.size})`
|
|
12776
12803
|
);
|
|
12777
|
-
await this.ensureObjectDetectionStream();
|
|
12804
|
+
await this.ensureObjectDetectionStream(key);
|
|
12778
12805
|
}
|
|
12779
12806
|
/**
|
|
12780
|
-
* Remove
|
|
12781
|
-
*
|
|
12807
|
+
* Remove a detection callback for a given `(channel, profile)` tuple — or,
|
|
12808
|
+
* if `options` is omitted, remove the callback from every active tuple. When
|
|
12809
|
+
* `callback` is also omitted, every listener on the targeted tuples is
|
|
12810
|
+
* cleared. The auto-managed substream of a tuple is closed when its last
|
|
12811
|
+
* listener is removed.
|
|
12782
12812
|
*/
|
|
12783
|
-
async offObjectDetections(callback) {
|
|
12784
|
-
|
|
12785
|
-
this.
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12813
|
+
async offObjectDetections(callback, options) {
|
|
12814
|
+
const targetKeys = options ? [
|
|
12815
|
+
this.objectDetectionKey(
|
|
12816
|
+
options.channel ?? 0,
|
|
12817
|
+
options.profile ?? "sub"
|
|
12818
|
+
)
|
|
12819
|
+
] : [...this.objectDetectionSubs.keys()];
|
|
12820
|
+
for (const key of targetKeys) {
|
|
12821
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12822
|
+
if (!entry) continue;
|
|
12823
|
+
if (callback) {
|
|
12824
|
+
entry.listeners.delete(callback);
|
|
12825
|
+
} else {
|
|
12826
|
+
entry.listeners.clear();
|
|
12827
|
+
}
|
|
12828
|
+
if (entry.listeners.size === 0) {
|
|
12829
|
+
await this.tearDownObjectDetectionStream(key);
|
|
12830
|
+
}
|
|
12791
12831
|
}
|
|
12792
12832
|
}
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12833
|
+
objectDetectionKey(channel, profile) {
|
|
12834
|
+
return `${channel}:${profile}`;
|
|
12835
|
+
}
|
|
12836
|
+
ensureObjectDetectionInternalListener() {
|
|
12837
|
+
if (this.objectDetectionInternalListener) return;
|
|
12838
|
+
const internal = (event) => {
|
|
12839
|
+
const key = this.objectDetectionKey(event.channel, event.profile);
|
|
12840
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12841
|
+
if (!entry || entry.listeners.size === 0) return;
|
|
12842
|
+
for (const cb of entry.listeners) {
|
|
12843
|
+
try {
|
|
12844
|
+
void Promise.resolve(cb(event)).catch((e) => {
|
|
12845
|
+
(this.logger.warn ?? this.logger.error).call(
|
|
12846
|
+
this.logger,
|
|
12847
|
+
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
12848
|
+
formatErrorForLog(e)
|
|
12849
|
+
);
|
|
12850
|
+
});
|
|
12851
|
+
} catch (e) {
|
|
12852
|
+
(this.logger.warn ?? this.logger.error).call(
|
|
12853
|
+
this.logger,
|
|
12854
|
+
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
12855
|
+
formatErrorForLog(e)
|
|
12856
|
+
);
|
|
12857
|
+
}
|
|
12858
|
+
}
|
|
12859
|
+
};
|
|
12860
|
+
this.objectDetectionInternalListener = internal;
|
|
12861
|
+
this.detectionEventListeners.add(internal);
|
|
12862
|
+
}
|
|
12863
|
+
maybeDropObjectDetectionInternalListener() {
|
|
12864
|
+
if (this.objectDetectionSubs.size > 0) return;
|
|
12865
|
+
if (!this.objectDetectionInternalListener) return;
|
|
12866
|
+
this.detectionEventListeners.delete(this.objectDetectionInternalListener);
|
|
12867
|
+
this.objectDetectionInternalListener = void 0;
|
|
12868
|
+
}
|
|
12869
|
+
async ensureObjectDetectionStream(key) {
|
|
12870
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12871
|
+
if (!entry) return;
|
|
12872
|
+
if (entry.stream) return;
|
|
12873
|
+
if (entry.startInFlight) {
|
|
12874
|
+
await entry.startInFlight;
|
|
12797
12875
|
return;
|
|
12798
12876
|
}
|
|
12799
|
-
|
|
12877
|
+
entry.startInFlight = (async () => {
|
|
12800
12878
|
const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-HGPU2MZ3.js");
|
|
12801
|
-
const sessionKey = `live:object-detections:
|
|
12879
|
+
const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
|
|
12802
12880
|
const dedicated = await this.createDedicatedSession(sessionKey);
|
|
12803
12881
|
const stream = new BaichuanVideoStream2({
|
|
12804
12882
|
client: dedicated.client,
|
|
12805
12883
|
api: this,
|
|
12806
|
-
channel:
|
|
12807
|
-
profile:
|
|
12884
|
+
channel: entry.channel,
|
|
12885
|
+
profile: entry.profile,
|
|
12808
12886
|
logger: this.logger
|
|
12809
12887
|
});
|
|
12810
|
-
this.
|
|
12811
|
-
for (const cb of this.objectDetectionListeners) {
|
|
12812
|
-
try {
|
|
12813
|
-
void Promise.resolve(cb(event)).catch((e) => {
|
|
12814
|
-
(this.logger.warn ?? this.logger.error).call(
|
|
12815
|
-
this.logger,
|
|
12816
|
-
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
12817
|
-
formatErrorForLog(e)
|
|
12818
|
-
);
|
|
12819
|
-
});
|
|
12820
|
-
} catch (e) {
|
|
12821
|
-
(this.logger.warn ?? this.logger.error).call(
|
|
12822
|
-
this.logger,
|
|
12823
|
-
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
12824
|
-
formatErrorForLog(e)
|
|
12825
|
-
);
|
|
12826
|
-
}
|
|
12827
|
-
}
|
|
12828
|
-
};
|
|
12829
|
-
this.detectionEventListeners.add(this.objectDetectionInternalListener);
|
|
12888
|
+
this.ensureObjectDetectionInternalListener();
|
|
12830
12889
|
try {
|
|
12831
12890
|
await stream.start();
|
|
12832
12891
|
} catch (e) {
|
|
12833
|
-
if (this.objectDetectionInternalListener) {
|
|
12834
|
-
this.detectionEventListeners.delete(
|
|
12835
|
-
this.objectDetectionInternalListener
|
|
12836
|
-
);
|
|
12837
|
-
this.objectDetectionInternalListener = void 0;
|
|
12838
|
-
}
|
|
12839
12892
|
await dedicated.release().catch(() => {
|
|
12840
12893
|
});
|
|
12894
|
+
this.maybeDropObjectDetectionInternalListener();
|
|
12841
12895
|
throw e;
|
|
12842
12896
|
}
|
|
12843
|
-
|
|
12897
|
+
entry.stream = {
|
|
12844
12898
|
stop: () => stream.stop(),
|
|
12845
12899
|
release: () => dedicated.release()
|
|
12846
12900
|
};
|
|
@@ -12849,35 +12903,36 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
12849
12903
|
);
|
|
12850
12904
|
})();
|
|
12851
12905
|
try {
|
|
12852
|
-
await
|
|
12906
|
+
await entry.startInFlight;
|
|
12853
12907
|
} finally {
|
|
12854
|
-
|
|
12908
|
+
delete entry.startInFlight;
|
|
12855
12909
|
}
|
|
12856
12910
|
}
|
|
12857
|
-
async tearDownObjectDetectionStream() {
|
|
12858
|
-
const
|
|
12859
|
-
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12863
|
-
|
|
12864
|
-
|
|
12865
|
-
|
|
12866
|
-
|
|
12867
|
-
|
|
12868
|
-
|
|
12869
|
-
|
|
12870
|
-
|
|
12871
|
-
|
|
12872
|
-
|
|
12873
|
-
|
|
12874
|
-
|
|
12875
|
-
|
|
12876
|
-
|
|
12877
|
-
|
|
12911
|
+
async tearDownObjectDetectionStream(key) {
|
|
12912
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12913
|
+
if (!entry) return;
|
|
12914
|
+
const handle = entry.stream;
|
|
12915
|
+
delete entry.stream;
|
|
12916
|
+
this.objectDetectionSubs.delete(key);
|
|
12917
|
+
if (handle) {
|
|
12918
|
+
try {
|
|
12919
|
+
await handle.stop();
|
|
12920
|
+
} catch (e) {
|
|
12921
|
+
this.logger.debug?.(
|
|
12922
|
+
`[ReolinkBaichuanApi] onObjectDetections: stream stop error (key=${key}): ${formatErrorForLog(e)}`
|
|
12923
|
+
);
|
|
12924
|
+
}
|
|
12925
|
+
try {
|
|
12926
|
+
await handle.release();
|
|
12927
|
+
} catch (e) {
|
|
12928
|
+
this.logger.debug?.(
|
|
12929
|
+
`[ReolinkBaichuanApi] onObjectDetections: session release error (key=${key}): ${formatErrorForLog(e)}`
|
|
12930
|
+
);
|
|
12931
|
+
}
|
|
12878
12932
|
}
|
|
12933
|
+
this.maybeDropObjectDetectionInternalListener();
|
|
12879
12934
|
this.logger.debug?.(
|
|
12880
|
-
`[ReolinkBaichuanApi] onObjectDetections: substream torn down`
|
|
12935
|
+
`[ReolinkBaichuanApi] onObjectDetections: substream torn down (key=${key})`
|
|
12881
12936
|
);
|
|
12882
12937
|
}
|
|
12883
12938
|
/**
|
|
@@ -13310,9 +13365,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
13310
13365
|
this.stopUdpSleepInference();
|
|
13311
13366
|
this.stopSimpleEventWatchdog();
|
|
13312
13367
|
this.stopSimpleEventResubscribeTimer();
|
|
13313
|
-
this.
|
|
13314
|
-
|
|
13315
|
-
|
|
13368
|
+
for (const key of [...this.objectDetectionSubs.keys()]) {
|
|
13369
|
+
await this.tearDownObjectDetectionStream(key).catch(() => {
|
|
13370
|
+
});
|
|
13371
|
+
}
|
|
13316
13372
|
await this.cleanup();
|
|
13317
13373
|
await this.stopAllActiveStreams();
|
|
13318
13374
|
await this.cleanupSocketPool();
|
|
@@ -18688,6 +18744,13 @@ ${xml}`
|
|
|
18688
18744
|
model = deviceInfo.type?.trim();
|
|
18689
18745
|
} catch {
|
|
18690
18746
|
}
|
|
18747
|
+
if (!model) {
|
|
18748
|
+
try {
|
|
18749
|
+
const deviceInfoBase = await this.getInfo(void 0, { tags: ["type"] });
|
|
18750
|
+
model = deviceInfoBase.type?.trim();
|
|
18751
|
+
} catch {
|
|
18752
|
+
}
|
|
18753
|
+
}
|
|
18691
18754
|
try {
|
|
18692
18755
|
const capabilities = await this.getDeviceCapabilities(channel);
|
|
18693
18756
|
channelNum = capabilities.support?.channelNum;
|
|
@@ -19393,7 +19456,7 @@ ${xml}`
|
|
|
19393
19456
|
* @returns Test results for all stream types and profiles
|
|
19394
19457
|
*/
|
|
19395
19458
|
async testChannelStreams(channel, logger) {
|
|
19396
|
-
const { testChannelStreams } = await import("./DiagnosticsTools-
|
|
19459
|
+
const { testChannelStreams } = await import("./DiagnosticsTools-HO3VI6D5.js");
|
|
19397
19460
|
return await testChannelStreams({
|
|
19398
19461
|
api: this,
|
|
19399
19462
|
channel: this.normalizeChannel(channel),
|
|
@@ -19409,7 +19472,7 @@ ${xml}`
|
|
|
19409
19472
|
* @returns Complete diagnostics for all channels and streams
|
|
19410
19473
|
*/
|
|
19411
19474
|
async collectMultifocalDiagnostics(logger) {
|
|
19412
|
-
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-
|
|
19475
|
+
const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-HO3VI6D5.js");
|
|
19413
19476
|
return await collectMultifocalDiagnostics({
|
|
19414
19477
|
api: this,
|
|
19415
19478
|
logger
|
|
@@ -23882,4 +23945,4 @@ export {
|
|
|
23882
23945
|
isTcpFailureThatShouldFallbackToUdp,
|
|
23883
23946
|
autoDetectDeviceType
|
|
23884
23947
|
};
|
|
23885
|
-
//# sourceMappingURL=chunk-
|
|
23948
|
+
//# sourceMappingURL=chunk-EF6BCSCZ.js.map
|