@apocaliss92/nodelink-js 0.4.14 → 0.4.16
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/{chunk-WKETZFBI.js → chunk-65HTCC62.js} +137 -90
- package/dist/chunk-65HTCC62.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +136 -89
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +1 -1
- package/dist/index.cjs +136 -89
- 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 +1 -1
- package/package.json +1 -1
- package/dist/chunk-WKETZFBI.js.map +0 -1
|
@@ -11285,14 +11285,15 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
11285
11285
|
// _registerVideoStreamForDetection (called from BaichuanVideoStream.start).
|
|
11286
11286
|
detectionEventListeners = /* @__PURE__ */ new Set();
|
|
11287
11287
|
detectionEventStreamHooks = /* @__PURE__ */ new Map();
|
|
11288
|
-
// Auto-managed
|
|
11289
|
-
//
|
|
11290
|
-
//
|
|
11291
|
-
//
|
|
11292
|
-
//
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11288
|
+
// Auto-managed substreams for `onObjectDetections` listeners. One entry per
|
|
11289
|
+
// `(channel, profile)` tuple — required for NVR/Hub setups where AI boxes
|
|
11290
|
+
// live on a specific channel, and for callers that need detections off a
|
|
11291
|
+
// profile other than the default `sub`. The substream is opened on the first
|
|
11292
|
+
// listener of a tuple and torn down when the last one for that tuple leaves.
|
|
11293
|
+
objectDetectionSubs = /* @__PURE__ */ new Map();
|
|
11294
|
+
// Single bridge installed into `detectionEventListeners` while at least one
|
|
11295
|
+
// object-detection subscription is active. It routes events to the correct
|
|
11296
|
+
// tuple's listener set based on `event.channel` / `event.profile`.
|
|
11296
11297
|
objectDetectionInternalListener;
|
|
11297
11298
|
simpleEventSubscribeInFlight;
|
|
11298
11299
|
simpleEventUnsubscribeInFlight;
|
|
@@ -12760,87 +12761,129 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
12760
12761
|
* Subscribe to AI object detections (people / vehicle / animal / face boxes
|
|
12761
12762
|
* with class label and confidence) without managing a video stream yourself.
|
|
12762
12763
|
*
|
|
12763
|
-
* Mirrors {@link onSimpleEvent} end-to-end: the
|
|
12764
|
-
*
|
|
12765
|
-
*
|
|
12766
|
-
*
|
|
12767
|
-
*
|
|
12764
|
+
* Mirrors {@link onSimpleEvent} end-to-end: on the first listener for a given
|
|
12765
|
+
* `(channel, profile)` tuple the API ensures the corresponding video stream
|
|
12766
|
+
* is running (the pool socket may already be shared with a regular consumer),
|
|
12767
|
+
* forwards every box-bearing `additionalHeader` to your callback, and tears
|
|
12768
|
+
* the stream down when the last listener for that tuple unsubscribes.
|
|
12769
|
+
*
|
|
12770
|
+
* Defaults — `channel: 0`, `profile: "sub"` — match a single-lens standalone
|
|
12771
|
+
* camera. **For NVR/Hub child cameras you must pass the channel explicitly**,
|
|
12772
|
+
* otherwise the substream opens on channel 0 and never sees the AI boxes for
|
|
12773
|
+
* the other channels. The `sub` profile is recommended (lighter bandwidth)
|
|
12774
|
+
* but `main` / `ext` are accepted if you specifically need detections off a
|
|
12775
|
+
* different feed.
|
|
12768
12776
|
*
|
|
12769
12777
|
* Each event carries normalized `[0, 1]` box coordinates, a class label, and
|
|
12770
12778
|
* a confidence score — render-ready without further conversion.
|
|
12771
12779
|
*/
|
|
12772
|
-
async onObjectDetections(callback) {
|
|
12773
|
-
|
|
12780
|
+
async onObjectDetections(callback, options) {
|
|
12781
|
+
const channel = options?.channel ?? 0;
|
|
12782
|
+
const profile = options?.profile ?? "sub";
|
|
12783
|
+
const key = this.objectDetectionKey(channel, profile);
|
|
12784
|
+
let entry = this.objectDetectionSubs.get(key);
|
|
12785
|
+
if (!entry) {
|
|
12786
|
+
entry = { channel, profile, listeners: /* @__PURE__ */ new Set() };
|
|
12787
|
+
this.objectDetectionSubs.set(key, entry);
|
|
12788
|
+
}
|
|
12789
|
+
entry.listeners.add(callback);
|
|
12774
12790
|
this.logger.debug?.(
|
|
12775
|
-
`[ReolinkBaichuanApi] onObjectDetections: registering listener (total=${
|
|
12791
|
+
`[ReolinkBaichuanApi] onObjectDetections: registering listener for ch${channel}/${profile} (total=${entry.listeners.size})`
|
|
12776
12792
|
);
|
|
12777
|
-
await this.ensureObjectDetectionStream();
|
|
12793
|
+
await this.ensureObjectDetectionStream(key);
|
|
12778
12794
|
}
|
|
12779
12795
|
/**
|
|
12780
|
-
* Remove
|
|
12781
|
-
*
|
|
12796
|
+
* Remove a detection callback for a given `(channel, profile)` tuple — or,
|
|
12797
|
+
* if `options` is omitted, remove the callback from every active tuple. When
|
|
12798
|
+
* `callback` is also omitted, every listener on the targeted tuples is
|
|
12799
|
+
* cleared. The auto-managed substream of a tuple is closed when its last
|
|
12800
|
+
* listener is removed.
|
|
12782
12801
|
*/
|
|
12783
|
-
async offObjectDetections(callback) {
|
|
12784
|
-
|
|
12785
|
-
this.
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12802
|
+
async offObjectDetections(callback, options) {
|
|
12803
|
+
const targetKeys = options ? [
|
|
12804
|
+
this.objectDetectionKey(
|
|
12805
|
+
options.channel ?? 0,
|
|
12806
|
+
options.profile ?? "sub"
|
|
12807
|
+
)
|
|
12808
|
+
] : [...this.objectDetectionSubs.keys()];
|
|
12809
|
+
for (const key of targetKeys) {
|
|
12810
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12811
|
+
if (!entry) continue;
|
|
12812
|
+
if (callback) {
|
|
12813
|
+
entry.listeners.delete(callback);
|
|
12814
|
+
} else {
|
|
12815
|
+
entry.listeners.clear();
|
|
12816
|
+
}
|
|
12817
|
+
if (entry.listeners.size === 0) {
|
|
12818
|
+
await this.tearDownObjectDetectionStream(key);
|
|
12819
|
+
}
|
|
12791
12820
|
}
|
|
12792
12821
|
}
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12822
|
+
objectDetectionKey(channel, profile) {
|
|
12823
|
+
return `${channel}:${profile}`;
|
|
12824
|
+
}
|
|
12825
|
+
ensureObjectDetectionInternalListener() {
|
|
12826
|
+
if (this.objectDetectionInternalListener) return;
|
|
12827
|
+
const internal = (event) => {
|
|
12828
|
+
const key = this.objectDetectionKey(event.channel, event.profile);
|
|
12829
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12830
|
+
if (!entry || entry.listeners.size === 0) return;
|
|
12831
|
+
for (const cb of entry.listeners) {
|
|
12832
|
+
try {
|
|
12833
|
+
void Promise.resolve(cb(event)).catch((e) => {
|
|
12834
|
+
(this.logger.warn ?? this.logger.error).call(
|
|
12835
|
+
this.logger,
|
|
12836
|
+
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
12837
|
+
formatErrorForLog(e)
|
|
12838
|
+
);
|
|
12839
|
+
});
|
|
12840
|
+
} catch (e) {
|
|
12841
|
+
(this.logger.warn ?? this.logger.error).call(
|
|
12842
|
+
this.logger,
|
|
12843
|
+
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
12844
|
+
formatErrorForLog(e)
|
|
12845
|
+
);
|
|
12846
|
+
}
|
|
12847
|
+
}
|
|
12848
|
+
};
|
|
12849
|
+
this.objectDetectionInternalListener = internal;
|
|
12850
|
+
this.detectionEventListeners.add(internal);
|
|
12851
|
+
}
|
|
12852
|
+
maybeDropObjectDetectionInternalListener() {
|
|
12853
|
+
if (this.objectDetectionSubs.size > 0) return;
|
|
12854
|
+
if (!this.objectDetectionInternalListener) return;
|
|
12855
|
+
this.detectionEventListeners.delete(this.objectDetectionInternalListener);
|
|
12856
|
+
this.objectDetectionInternalListener = void 0;
|
|
12857
|
+
}
|
|
12858
|
+
async ensureObjectDetectionStream(key) {
|
|
12859
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12860
|
+
if (!entry) return;
|
|
12861
|
+
if (entry.stream) return;
|
|
12862
|
+
if (entry.startInFlight) {
|
|
12863
|
+
await entry.startInFlight;
|
|
12797
12864
|
return;
|
|
12798
12865
|
}
|
|
12799
|
-
|
|
12866
|
+
entry.startInFlight = (async () => {
|
|
12800
12867
|
const { BaichuanVideoStream: BaichuanVideoStream2 } = await import("./BaichuanVideoStream-HGPU2MZ3.js");
|
|
12801
|
-
const sessionKey = `live:object-detections:
|
|
12868
|
+
const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
|
|
12802
12869
|
const dedicated = await this.createDedicatedSession(sessionKey);
|
|
12803
12870
|
const stream = new BaichuanVideoStream2({
|
|
12804
12871
|
client: dedicated.client,
|
|
12805
12872
|
api: this,
|
|
12806
|
-
channel:
|
|
12807
|
-
profile:
|
|
12873
|
+
channel: entry.channel,
|
|
12874
|
+
profile: entry.profile,
|
|
12808
12875
|
logger: this.logger
|
|
12809
12876
|
});
|
|
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);
|
|
12877
|
+
this.ensureObjectDetectionInternalListener();
|
|
12830
12878
|
try {
|
|
12831
12879
|
await stream.start();
|
|
12832
12880
|
} catch (e) {
|
|
12833
|
-
if (this.objectDetectionInternalListener) {
|
|
12834
|
-
this.detectionEventListeners.delete(
|
|
12835
|
-
this.objectDetectionInternalListener
|
|
12836
|
-
);
|
|
12837
|
-
this.objectDetectionInternalListener = void 0;
|
|
12838
|
-
}
|
|
12839
12881
|
await dedicated.release().catch(() => {
|
|
12840
12882
|
});
|
|
12883
|
+
this.maybeDropObjectDetectionInternalListener();
|
|
12841
12884
|
throw e;
|
|
12842
12885
|
}
|
|
12843
|
-
|
|
12886
|
+
entry.stream = {
|
|
12844
12887
|
stop: () => stream.stop(),
|
|
12845
12888
|
release: () => dedicated.release()
|
|
12846
12889
|
};
|
|
@@ -12849,35 +12892,36 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
12849
12892
|
);
|
|
12850
12893
|
})();
|
|
12851
12894
|
try {
|
|
12852
|
-
await
|
|
12895
|
+
await entry.startInFlight;
|
|
12853
12896
|
} finally {
|
|
12854
|
-
|
|
12897
|
+
delete entry.startInFlight;
|
|
12855
12898
|
}
|
|
12856
12899
|
}
|
|
12857
|
-
async tearDownObjectDetectionStream() {
|
|
12858
|
-
const
|
|
12859
|
-
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12863
|
-
|
|
12864
|
-
|
|
12865
|
-
|
|
12866
|
-
|
|
12867
|
-
|
|
12868
|
-
|
|
12869
|
-
|
|
12870
|
-
|
|
12871
|
-
|
|
12872
|
-
|
|
12873
|
-
|
|
12874
|
-
|
|
12875
|
-
|
|
12876
|
-
|
|
12877
|
-
|
|
12900
|
+
async tearDownObjectDetectionStream(key) {
|
|
12901
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
12902
|
+
if (!entry) return;
|
|
12903
|
+
const handle = entry.stream;
|
|
12904
|
+
delete entry.stream;
|
|
12905
|
+
this.objectDetectionSubs.delete(key);
|
|
12906
|
+
if (handle) {
|
|
12907
|
+
try {
|
|
12908
|
+
await handle.stop();
|
|
12909
|
+
} catch (e) {
|
|
12910
|
+
this.logger.debug?.(
|
|
12911
|
+
`[ReolinkBaichuanApi] onObjectDetections: stream stop error (key=${key}): ${formatErrorForLog(e)}`
|
|
12912
|
+
);
|
|
12913
|
+
}
|
|
12914
|
+
try {
|
|
12915
|
+
await handle.release();
|
|
12916
|
+
} catch (e) {
|
|
12917
|
+
this.logger.debug?.(
|
|
12918
|
+
`[ReolinkBaichuanApi] onObjectDetections: session release error (key=${key}): ${formatErrorForLog(e)}`
|
|
12919
|
+
);
|
|
12920
|
+
}
|
|
12878
12921
|
}
|
|
12922
|
+
this.maybeDropObjectDetectionInternalListener();
|
|
12879
12923
|
this.logger.debug?.(
|
|
12880
|
-
`[ReolinkBaichuanApi] onObjectDetections: substream torn down`
|
|
12924
|
+
`[ReolinkBaichuanApi] onObjectDetections: substream torn down (key=${key})`
|
|
12881
12925
|
);
|
|
12882
12926
|
}
|
|
12883
12927
|
/**
|
|
@@ -13310,9 +13354,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
13310
13354
|
this.stopUdpSleepInference();
|
|
13311
13355
|
this.stopSimpleEventWatchdog();
|
|
13312
13356
|
this.stopSimpleEventResubscribeTimer();
|
|
13313
|
-
this.
|
|
13314
|
-
|
|
13315
|
-
|
|
13357
|
+
for (const key of [...this.objectDetectionSubs.keys()]) {
|
|
13358
|
+
await this.tearDownObjectDetectionStream(key).catch(() => {
|
|
13359
|
+
});
|
|
13360
|
+
}
|
|
13316
13361
|
await this.cleanup();
|
|
13317
13362
|
await this.stopAllActiveStreams();
|
|
13318
13363
|
await this.cleanupSocketPool();
|
|
@@ -19793,6 +19838,7 @@ ${xml}`
|
|
|
19793
19838
|
async setAutoFocus(channel, disable, options) {
|
|
19794
19839
|
const ch = this.normalizeChannel(channel);
|
|
19795
19840
|
const disableVal = disable ? 1 : 0;
|
|
19841
|
+
const extensionXml = buildChannelExtensionXml(ch);
|
|
19796
19842
|
const payloadXml = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
19797
19843
|
<body>
|
|
19798
19844
|
<AutoFocus version="1.1">
|
|
@@ -19803,6 +19849,7 @@ ${xml}`
|
|
|
19803
19849
|
await this.sendXml({
|
|
19804
19850
|
cmdId: BC_CMD_ID_SET_AUTO_FOCUS,
|
|
19805
19851
|
channel: ch,
|
|
19852
|
+
extensionXml,
|
|
19806
19853
|
payloadXml,
|
|
19807
19854
|
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
19808
19855
|
});
|
|
@@ -23880,4 +23927,4 @@ export {
|
|
|
23880
23927
|
isTcpFailureThatShouldFallbackToUdp,
|
|
23881
23928
|
autoDetectDeviceType
|
|
23882
23929
|
};
|
|
23883
|
-
//# sourceMappingURL=chunk-
|
|
23930
|
+
//# sourceMappingURL=chunk-65HTCC62.js.map
|