@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
package/dist/cli/rtsp-server.cjs
CHANGED
|
@@ -18939,14 +18939,15 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
18939
18939
|
// _registerVideoStreamForDetection (called from BaichuanVideoStream.start).
|
|
18940
18940
|
detectionEventListeners = /* @__PURE__ */ new Set();
|
|
18941
18941
|
detectionEventStreamHooks = /* @__PURE__ */ new Map();
|
|
18942
|
-
// Auto-managed
|
|
18943
|
-
//
|
|
18944
|
-
//
|
|
18945
|
-
//
|
|
18946
|
-
//
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
|
|
18942
|
+
// Auto-managed substreams for `onObjectDetections` listeners. One entry per
|
|
18943
|
+
// `(channel, profile)` tuple — required for NVR/Hub setups where AI boxes
|
|
18944
|
+
// live on a specific channel, and for callers that need detections off a
|
|
18945
|
+
// profile other than the default `sub`. The substream is opened on the first
|
|
18946
|
+
// listener of a tuple and torn down when the last one for that tuple leaves.
|
|
18947
|
+
objectDetectionSubs = /* @__PURE__ */ new Map();
|
|
18948
|
+
// Single bridge installed into `detectionEventListeners` while at least one
|
|
18949
|
+
// object-detection subscription is active. It routes events to the correct
|
|
18950
|
+
// tuple's listener set based on `event.channel` / `event.profile`.
|
|
18950
18951
|
objectDetectionInternalListener;
|
|
18951
18952
|
simpleEventSubscribeInFlight;
|
|
18952
18953
|
simpleEventUnsubscribeInFlight;
|
|
@@ -20414,87 +20415,129 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
20414
20415
|
* Subscribe to AI object detections (people / vehicle / animal / face boxes
|
|
20415
20416
|
* with class label and confidence) without managing a video stream yourself.
|
|
20416
20417
|
*
|
|
20417
|
-
* Mirrors {@link onSimpleEvent} end-to-end: the
|
|
20418
|
-
*
|
|
20419
|
-
*
|
|
20420
|
-
*
|
|
20421
|
-
*
|
|
20418
|
+
* Mirrors {@link onSimpleEvent} end-to-end: on the first listener for a given
|
|
20419
|
+
* `(channel, profile)` tuple the API ensures the corresponding video stream
|
|
20420
|
+
* is running (the pool socket may already be shared with a regular consumer),
|
|
20421
|
+
* forwards every box-bearing `additionalHeader` to your callback, and tears
|
|
20422
|
+
* the stream down when the last listener for that tuple unsubscribes.
|
|
20423
|
+
*
|
|
20424
|
+
* Defaults — `channel: 0`, `profile: "sub"` — match a single-lens standalone
|
|
20425
|
+
* camera. **For NVR/Hub child cameras you must pass the channel explicitly**,
|
|
20426
|
+
* otherwise the substream opens on channel 0 and never sees the AI boxes for
|
|
20427
|
+
* the other channels. The `sub` profile is recommended (lighter bandwidth)
|
|
20428
|
+
* but `main` / `ext` are accepted if you specifically need detections off a
|
|
20429
|
+
* different feed.
|
|
20422
20430
|
*
|
|
20423
20431
|
* Each event carries normalized `[0, 1]` box coordinates, a class label, and
|
|
20424
20432
|
* a confidence score — render-ready without further conversion.
|
|
20425
20433
|
*/
|
|
20426
|
-
async onObjectDetections(callback) {
|
|
20427
|
-
|
|
20434
|
+
async onObjectDetections(callback, options) {
|
|
20435
|
+
const channel = options?.channel ?? 0;
|
|
20436
|
+
const profile = options?.profile ?? "sub";
|
|
20437
|
+
const key = this.objectDetectionKey(channel, profile);
|
|
20438
|
+
let entry = this.objectDetectionSubs.get(key);
|
|
20439
|
+
if (!entry) {
|
|
20440
|
+
entry = { channel, profile, listeners: /* @__PURE__ */ new Set() };
|
|
20441
|
+
this.objectDetectionSubs.set(key, entry);
|
|
20442
|
+
}
|
|
20443
|
+
entry.listeners.add(callback);
|
|
20428
20444
|
this.logger.debug?.(
|
|
20429
|
-
`[ReolinkBaichuanApi] onObjectDetections: registering listener (total=${
|
|
20445
|
+
`[ReolinkBaichuanApi] onObjectDetections: registering listener for ch${channel}/${profile} (total=${entry.listeners.size})`
|
|
20430
20446
|
);
|
|
20431
|
-
await this.ensureObjectDetectionStream();
|
|
20447
|
+
await this.ensureObjectDetectionStream(key);
|
|
20432
20448
|
}
|
|
20433
20449
|
/**
|
|
20434
|
-
* Remove
|
|
20435
|
-
*
|
|
20450
|
+
* Remove a detection callback for a given `(channel, profile)` tuple — or,
|
|
20451
|
+
* if `options` is omitted, remove the callback from every active tuple. When
|
|
20452
|
+
* `callback` is also omitted, every listener on the targeted tuples is
|
|
20453
|
+
* cleared. The auto-managed substream of a tuple is closed when its last
|
|
20454
|
+
* listener is removed.
|
|
20436
20455
|
*/
|
|
20437
|
-
async offObjectDetections(callback) {
|
|
20438
|
-
|
|
20439
|
-
this.
|
|
20440
|
-
|
|
20441
|
-
|
|
20442
|
-
|
|
20443
|
-
|
|
20444
|
-
|
|
20456
|
+
async offObjectDetections(callback, options) {
|
|
20457
|
+
const targetKeys = options ? [
|
|
20458
|
+
this.objectDetectionKey(
|
|
20459
|
+
options.channel ?? 0,
|
|
20460
|
+
options.profile ?? "sub"
|
|
20461
|
+
)
|
|
20462
|
+
] : [...this.objectDetectionSubs.keys()];
|
|
20463
|
+
for (const key of targetKeys) {
|
|
20464
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
20465
|
+
if (!entry) continue;
|
|
20466
|
+
if (callback) {
|
|
20467
|
+
entry.listeners.delete(callback);
|
|
20468
|
+
} else {
|
|
20469
|
+
entry.listeners.clear();
|
|
20470
|
+
}
|
|
20471
|
+
if (entry.listeners.size === 0) {
|
|
20472
|
+
await this.tearDownObjectDetectionStream(key);
|
|
20473
|
+
}
|
|
20445
20474
|
}
|
|
20446
20475
|
}
|
|
20447
|
-
|
|
20448
|
-
|
|
20449
|
-
|
|
20450
|
-
|
|
20476
|
+
objectDetectionKey(channel, profile) {
|
|
20477
|
+
return `${channel}:${profile}`;
|
|
20478
|
+
}
|
|
20479
|
+
ensureObjectDetectionInternalListener() {
|
|
20480
|
+
if (this.objectDetectionInternalListener) return;
|
|
20481
|
+
const internal = (event) => {
|
|
20482
|
+
const key = this.objectDetectionKey(event.channel, event.profile);
|
|
20483
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
20484
|
+
if (!entry || entry.listeners.size === 0) return;
|
|
20485
|
+
for (const cb of entry.listeners) {
|
|
20486
|
+
try {
|
|
20487
|
+
void Promise.resolve(cb(event)).catch((e) => {
|
|
20488
|
+
(this.logger.warn ?? this.logger.error).call(
|
|
20489
|
+
this.logger,
|
|
20490
|
+
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
20491
|
+
formatErrorForLog(e)
|
|
20492
|
+
);
|
|
20493
|
+
});
|
|
20494
|
+
} catch (e) {
|
|
20495
|
+
(this.logger.warn ?? this.logger.error).call(
|
|
20496
|
+
this.logger,
|
|
20497
|
+
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
20498
|
+
formatErrorForLog(e)
|
|
20499
|
+
);
|
|
20500
|
+
}
|
|
20501
|
+
}
|
|
20502
|
+
};
|
|
20503
|
+
this.objectDetectionInternalListener = internal;
|
|
20504
|
+
this.detectionEventListeners.add(internal);
|
|
20505
|
+
}
|
|
20506
|
+
maybeDropObjectDetectionInternalListener() {
|
|
20507
|
+
if (this.objectDetectionSubs.size > 0) return;
|
|
20508
|
+
if (!this.objectDetectionInternalListener) return;
|
|
20509
|
+
this.detectionEventListeners.delete(this.objectDetectionInternalListener);
|
|
20510
|
+
this.objectDetectionInternalListener = void 0;
|
|
20511
|
+
}
|
|
20512
|
+
async ensureObjectDetectionStream(key) {
|
|
20513
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
20514
|
+
if (!entry) return;
|
|
20515
|
+
if (entry.stream) return;
|
|
20516
|
+
if (entry.startInFlight) {
|
|
20517
|
+
await entry.startInFlight;
|
|
20451
20518
|
return;
|
|
20452
20519
|
}
|
|
20453
|
-
|
|
20520
|
+
entry.startInFlight = (async () => {
|
|
20454
20521
|
const { BaichuanVideoStream: BaichuanVideoStream2 } = await Promise.resolve().then(() => (init_BaichuanVideoStream(), BaichuanVideoStream_exports));
|
|
20455
|
-
const sessionKey = `live:object-detections:
|
|
20522
|
+
const sessionKey = `live:object-detections:ch${entry.channel}:${entry.profile}`;
|
|
20456
20523
|
const dedicated = await this.createDedicatedSession(sessionKey);
|
|
20457
20524
|
const stream = new BaichuanVideoStream2({
|
|
20458
20525
|
client: dedicated.client,
|
|
20459
20526
|
api: this,
|
|
20460
|
-
channel:
|
|
20461
|
-
profile:
|
|
20527
|
+
channel: entry.channel,
|
|
20528
|
+
profile: entry.profile,
|
|
20462
20529
|
logger: this.logger
|
|
20463
20530
|
});
|
|
20464
|
-
this.
|
|
20465
|
-
for (const cb of this.objectDetectionListeners) {
|
|
20466
|
-
try {
|
|
20467
|
-
void Promise.resolve(cb(event)).catch((e) => {
|
|
20468
|
-
(this.logger.warn ?? this.logger.error).call(
|
|
20469
|
-
this.logger,
|
|
20470
|
-
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
20471
|
-
formatErrorForLog(e)
|
|
20472
|
-
);
|
|
20473
|
-
});
|
|
20474
|
-
} catch (e) {
|
|
20475
|
-
(this.logger.warn ?? this.logger.error).call(
|
|
20476
|
-
this.logger,
|
|
20477
|
-
"[ReolinkBaichuanApi] onObjectDetections handler error",
|
|
20478
|
-
formatErrorForLog(e)
|
|
20479
|
-
);
|
|
20480
|
-
}
|
|
20481
|
-
}
|
|
20482
|
-
};
|
|
20483
|
-
this.detectionEventListeners.add(this.objectDetectionInternalListener);
|
|
20531
|
+
this.ensureObjectDetectionInternalListener();
|
|
20484
20532
|
try {
|
|
20485
20533
|
await stream.start();
|
|
20486
20534
|
} catch (e) {
|
|
20487
|
-
if (this.objectDetectionInternalListener) {
|
|
20488
|
-
this.detectionEventListeners.delete(
|
|
20489
|
-
this.objectDetectionInternalListener
|
|
20490
|
-
);
|
|
20491
|
-
this.objectDetectionInternalListener = void 0;
|
|
20492
|
-
}
|
|
20493
20535
|
await dedicated.release().catch(() => {
|
|
20494
20536
|
});
|
|
20537
|
+
this.maybeDropObjectDetectionInternalListener();
|
|
20495
20538
|
throw e;
|
|
20496
20539
|
}
|
|
20497
|
-
|
|
20540
|
+
entry.stream = {
|
|
20498
20541
|
stop: () => stream.stop(),
|
|
20499
20542
|
release: () => dedicated.release()
|
|
20500
20543
|
};
|
|
@@ -20503,35 +20546,36 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
20503
20546
|
);
|
|
20504
20547
|
})();
|
|
20505
20548
|
try {
|
|
20506
|
-
await
|
|
20549
|
+
await entry.startInFlight;
|
|
20507
20550
|
} finally {
|
|
20508
|
-
|
|
20551
|
+
delete entry.startInFlight;
|
|
20509
20552
|
}
|
|
20510
20553
|
}
|
|
20511
|
-
async tearDownObjectDetectionStream() {
|
|
20512
|
-
const
|
|
20513
|
-
|
|
20514
|
-
|
|
20515
|
-
|
|
20516
|
-
|
|
20517
|
-
|
|
20518
|
-
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
20524
|
-
|
|
20525
|
-
|
|
20526
|
-
|
|
20527
|
-
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20554
|
+
async tearDownObjectDetectionStream(key) {
|
|
20555
|
+
const entry = this.objectDetectionSubs.get(key);
|
|
20556
|
+
if (!entry) return;
|
|
20557
|
+
const handle = entry.stream;
|
|
20558
|
+
delete entry.stream;
|
|
20559
|
+
this.objectDetectionSubs.delete(key);
|
|
20560
|
+
if (handle) {
|
|
20561
|
+
try {
|
|
20562
|
+
await handle.stop();
|
|
20563
|
+
} catch (e) {
|
|
20564
|
+
this.logger.debug?.(
|
|
20565
|
+
`[ReolinkBaichuanApi] onObjectDetections: stream stop error (key=${key}): ${formatErrorForLog(e)}`
|
|
20566
|
+
);
|
|
20567
|
+
}
|
|
20568
|
+
try {
|
|
20569
|
+
await handle.release();
|
|
20570
|
+
} catch (e) {
|
|
20571
|
+
this.logger.debug?.(
|
|
20572
|
+
`[ReolinkBaichuanApi] onObjectDetections: session release error (key=${key}): ${formatErrorForLog(e)}`
|
|
20573
|
+
);
|
|
20574
|
+
}
|
|
20532
20575
|
}
|
|
20576
|
+
this.maybeDropObjectDetectionInternalListener();
|
|
20533
20577
|
this.logger.debug?.(
|
|
20534
|
-
`[ReolinkBaichuanApi] onObjectDetections: substream torn down`
|
|
20578
|
+
`[ReolinkBaichuanApi] onObjectDetections: substream torn down (key=${key})`
|
|
20535
20579
|
);
|
|
20536
20580
|
}
|
|
20537
20581
|
/**
|
|
@@ -20964,9 +21008,10 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
20964
21008
|
this.stopUdpSleepInference();
|
|
20965
21009
|
this.stopSimpleEventWatchdog();
|
|
20966
21010
|
this.stopSimpleEventResubscribeTimer();
|
|
20967
|
-
this.
|
|
20968
|
-
|
|
20969
|
-
|
|
21011
|
+
for (const key of [...this.objectDetectionSubs.keys()]) {
|
|
21012
|
+
await this.tearDownObjectDetectionStream(key).catch(() => {
|
|
21013
|
+
});
|
|
21014
|
+
}
|
|
20970
21015
|
await this.cleanup();
|
|
20971
21016
|
await this.stopAllActiveStreams();
|
|
20972
21017
|
await this.cleanupSocketPool();
|
|
@@ -27447,6 +27492,7 @@ ${xml}`
|
|
|
27447
27492
|
async setAutoFocus(channel, disable, options) {
|
|
27448
27493
|
const ch = this.normalizeChannel(channel);
|
|
27449
27494
|
const disableVal = disable ? 1 : 0;
|
|
27495
|
+
const extensionXml = buildChannelExtensionXml(ch);
|
|
27450
27496
|
const payloadXml = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
27451
27497
|
<body>
|
|
27452
27498
|
<AutoFocus version="1.1">
|
|
@@ -27457,6 +27503,7 @@ ${xml}`
|
|
|
27457
27503
|
await this.sendXml({
|
|
27458
27504
|
cmdId: BC_CMD_ID_SET_AUTO_FOCUS,
|
|
27459
27505
|
channel: ch,
|
|
27506
|
+
extensionXml,
|
|
27460
27507
|
payloadXml,
|
|
27461
27508
|
...options?.timeoutMs != null ? { timeoutMs: options.timeoutMs } : {}
|
|
27462
27509
|
});
|