@apocaliss92/nodelink-js 0.6.5 → 0.6.7
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-WQ2TQCYP.js → chunk-T22QCNBR.js} +114 -28
- package/dist/chunk-T22QCNBR.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +113 -27
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +1 -1
- package/dist/index.cjs +135 -854
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -196
- package/dist/index.d.ts +10 -175
- package/dist/index.js +21 -823
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-WQ2TQCYP.js.map +0 -1
package/dist/cli/rtsp-server.cjs
CHANGED
|
@@ -8836,6 +8836,38 @@ function createRtspFlow(transport, videoType) {
|
|
|
8836
8836
|
return new H265Flow(transport);
|
|
8837
8837
|
}
|
|
8838
8838
|
|
|
8839
|
+
// src/baichuan/stream/rtpVideoTimestamp.ts
|
|
8840
|
+
var U32 = 4294967296;
|
|
8841
|
+
var DEFAULT_VIDEO_CLOCK_RATE = 9e4;
|
|
8842
|
+
function deriveRtpVideoTimestamp(state, frameMicroseconds, clockRate = DEFAULT_VIDEO_CLOCK_RATE) {
|
|
8843
|
+
if (frameMicroseconds === null || frameMicroseconds === void 0 || !Number.isFinite(frameMicroseconds)) {
|
|
8844
|
+
return { timestamp: state.timestamp, state };
|
|
8845
|
+
}
|
|
8846
|
+
const curRaw = frameMicroseconds >>> 0;
|
|
8847
|
+
if (state.baseUnwrappedUs === void 0) {
|
|
8848
|
+
return {
|
|
8849
|
+
timestamp: state.timestamp,
|
|
8850
|
+
state: {
|
|
8851
|
+
...state,
|
|
8852
|
+
unwrappedUs: curRaw,
|
|
8853
|
+
lastRawUs: curRaw,
|
|
8854
|
+
baseUnwrappedUs: curRaw,
|
|
8855
|
+
baseTimestamp: state.timestamp
|
|
8856
|
+
}
|
|
8857
|
+
};
|
|
8858
|
+
}
|
|
8859
|
+
const lastRaw = state.lastRawUs ?? curRaw;
|
|
8860
|
+
let forwardDelta = curRaw - lastRaw >>> 0;
|
|
8861
|
+
if (forwardDelta > U32 / 2) forwardDelta = 0;
|
|
8862
|
+
const unwrappedUs = (state.unwrappedUs ?? curRaw) + forwardDelta;
|
|
8863
|
+
const deltaUs = unwrappedUs - state.baseUnwrappedUs;
|
|
8864
|
+
const timestamp = state.baseTimestamp + Math.round(deltaUs * clockRate / 1e6) >>> 0;
|
|
8865
|
+
return {
|
|
8866
|
+
timestamp,
|
|
8867
|
+
state: { ...state, unwrappedUs, lastRawUs: curRaw, timestamp }
|
|
8868
|
+
};
|
|
8869
|
+
}
|
|
8870
|
+
|
|
8839
8871
|
// src/baichuan/stream/BaichuanRtspServer.ts
|
|
8840
8872
|
init_H264Converter();
|
|
8841
8873
|
init_H265Converter();
|
|
@@ -9410,7 +9442,10 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events3.E
|
|
|
9410
9442
|
let useTcpInterleaved = false;
|
|
9411
9443
|
let clientUdpSocket = null;
|
|
9412
9444
|
let clientUdpSocketAudio = null;
|
|
9445
|
+
let cleanedUp = false;
|
|
9413
9446
|
const cleanup = () => {
|
|
9447
|
+
if (cleanedUp) return;
|
|
9448
|
+
cleanedUp = true;
|
|
9414
9449
|
const sessionDurationMs = Date.now() - connectTime;
|
|
9415
9450
|
const res = this.clientResources.get(clientId);
|
|
9416
9451
|
const framesSent = res?.framesSent ?? 0;
|
|
@@ -10158,22 +10193,25 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events3.E
|
|
|
10158
10193
|
resources.rtpVideoTimestamp = 0;
|
|
10159
10194
|
if (resources.rtpVideoBaseTimestamp === void 0)
|
|
10160
10195
|
resources.rtpVideoBaseTimestamp = resources.rtpVideoTimestamp;
|
|
10161
|
-
|
|
10196
|
+
const { timestamp, state } = deriveRtpVideoTimestamp(
|
|
10197
|
+
{
|
|
10198
|
+
timestamp: resources.rtpVideoTimestamp,
|
|
10199
|
+
baseTimestamp: resources.rtpVideoBaseTimestamp,
|
|
10200
|
+
unwrappedUs: resources.rtpVideoUnwrappedUs,
|
|
10201
|
+
lastRawUs: resources.rtpVideoLastRawUs,
|
|
10202
|
+
baseUnwrappedUs: resources.rtpVideoBaseUnwrappedUs
|
|
10203
|
+
},
|
|
10204
|
+
frameMicroseconds,
|
|
10205
|
+
videoClockRate
|
|
10206
|
+
);
|
|
10207
|
+
resources.rtpVideoTimestamp = timestamp;
|
|
10208
|
+
resources.rtpVideoBaseTimestamp = state.baseTimestamp;
|
|
10209
|
+
resources.rtpVideoUnwrappedUs = state.unwrappedUs;
|
|
10210
|
+
resources.rtpVideoLastRawUs = state.lastRawUs;
|
|
10211
|
+
resources.rtpVideoBaseUnwrappedUs = state.baseUnwrappedUs;
|
|
10212
|
+
resources.rtpVideoLastTimestamp = timestamp;
|
|
10213
|
+
if (resources.rtpVideoBaseMicroseconds === void 0)
|
|
10162
10214
|
resources.rtpVideoBaseMicroseconds = frameMicroseconds >>> 0;
|
|
10163
|
-
resources.rtpVideoLastTimestamp = resources.rtpVideoTimestamp;
|
|
10164
|
-
return;
|
|
10165
|
-
}
|
|
10166
|
-
const baseUs = resources.rtpVideoBaseMicroseconds >>> 0;
|
|
10167
|
-
const curUs = frameMicroseconds >>> 0;
|
|
10168
|
-
const deltaUs = curUs - baseUs >>> 0;
|
|
10169
|
-
const baseTs = (resources.rtpVideoBaseTimestamp ?? 0) >>> 0;
|
|
10170
|
-
let ts = baseTs + Math.round(deltaUs * videoClockRate / 1e6) >>> 0;
|
|
10171
|
-
const last = resources.rtpVideoLastTimestamp;
|
|
10172
|
-
if (last !== void 0 && ts <= last >>> 0) {
|
|
10173
|
-
ts = (last >>> 0) + 1 >>> 0;
|
|
10174
|
-
}
|
|
10175
|
-
resources.rtpVideoTimestamp = ts;
|
|
10176
|
-
resources.rtpVideoLastTimestamp = ts;
|
|
10177
10215
|
};
|
|
10178
10216
|
const sendVideoAccessUnit = (videoType, accessUnitAnnexB, advanceTimestamp = true) => {
|
|
10179
10217
|
const nals = _BaichuanRtspServer.splitAnnexBNals(accessUnitAnnexB);
|
|
@@ -17027,6 +17065,30 @@ function buildSetNtpXml(current, patch) {
|
|
|
17027
17065
|
);
|
|
17028
17066
|
}
|
|
17029
17067
|
|
|
17068
|
+
// src/reolink/baichuan/utils/channelEnumeration.ts
|
|
17069
|
+
async function resolveBaichuanChannels(deps) {
|
|
17070
|
+
const fromPush = dedupeSorted(deps.pushChannels);
|
|
17071
|
+
if (fromPush.length > 0) return fromPush;
|
|
17072
|
+
const slots = dedupeSorted(deps.supportChnIds);
|
|
17073
|
+
const candidates = slots.length > 0 ? slots : [0];
|
|
17074
|
+
const probed = await Promise.all(
|
|
17075
|
+
candidates.map(
|
|
17076
|
+
async (channel) => await deps.probe(channel) ? channel : void 0
|
|
17077
|
+
)
|
|
17078
|
+
);
|
|
17079
|
+
return dedupeSorted(
|
|
17080
|
+
probed.filter((c) => c !== void 0)
|
|
17081
|
+
);
|
|
17082
|
+
}
|
|
17083
|
+
function dedupeSorted(values) {
|
|
17084
|
+
const set = /* @__PURE__ */ new Set();
|
|
17085
|
+
for (const v of values) {
|
|
17086
|
+
const n = Number(v);
|
|
17087
|
+
if (Number.isFinite(n) && n >= 0) set.add(n);
|
|
17088
|
+
}
|
|
17089
|
+
return [...set].sort((a, b) => a - b);
|
|
17090
|
+
}
|
|
17091
|
+
|
|
17030
17092
|
// src/reolink/baichuan/utils/dst.ts
|
|
17031
17093
|
init_xml();
|
|
17032
17094
|
var parseNumberSafe3 = (text) => {
|
|
@@ -23405,13 +23467,21 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
23405
23467
|
* @param options.source - Data source for the channel list (default: `"cgi"`):
|
|
23406
23468
|
* - `"cgi"`: Uses HTTP `GetChannelstatus` — returns the channel list immediately,
|
|
23407
23469
|
* no dependency on async push messages. Recommended for first-call discovery.
|
|
23408
|
-
* - `"baichuan"`:
|
|
23409
|
-
*
|
|
23410
|
-
*
|
|
23411
|
-
*
|
|
23470
|
+
* - `"baichuan"`: HTTP-free discovery. Prefers the cmd_id 145 push cache when
|
|
23471
|
+
* populated; otherwise actively probes the channel slots advertised by Support
|
|
23472
|
+
* (`items[].chnID`) via `getInfo`. Use this for hubs with HTTP disabled.
|
|
23473
|
+
*
|
|
23474
|
+
* When the api was constructed with `nativeOnly`, the source is forced to
|
|
23475
|
+
* `"baichuan"` regardless of this option (no HTTP/CGI is ever attempted).
|
|
23412
23476
|
*/
|
|
23413
23477
|
async getNvrChannelsSummary(options) {
|
|
23414
|
-
const source = options?.source ?? "cgi";
|
|
23478
|
+
const source = this.nativeOnly ? "baichuan" : options?.source ?? "cgi";
|
|
23479
|
+
const support = await this.getSupportInfo().catch(() => {
|
|
23480
|
+
this.logger.error?.(
|
|
23481
|
+
"[ReolinkBaichuanApi] getNvrChannelsSummary: failed to get support info"
|
|
23482
|
+
);
|
|
23483
|
+
return void 0;
|
|
23484
|
+
});
|
|
23415
23485
|
let channels;
|
|
23416
23486
|
const cgiStatusByChannel = /* @__PURE__ */ new Map();
|
|
23417
23487
|
if (options?.channels?.length) {
|
|
@@ -23441,15 +23511,31 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
|
|
|
23441
23511
|
channels = [];
|
|
23442
23512
|
}
|
|
23443
23513
|
} else {
|
|
23444
|
-
const
|
|
23445
|
-
|
|
23514
|
+
const pushChannels = Array.from(
|
|
23515
|
+
this.getChannelInfoFromPushCache().keys()
|
|
23516
|
+
).map((c) => Number(c)).filter((n) => Number.isFinite(n));
|
|
23517
|
+
const supportChnIds = (support?.items ?? []).map((i) => Number(i.chnID)).filter((n) => Number.isFinite(n));
|
|
23518
|
+
const probeTimeoutMs = options?.timeoutMs ?? 2500;
|
|
23519
|
+
channels = await resolveBaichuanChannels({
|
|
23520
|
+
pushChannels,
|
|
23521
|
+
supportChnIds,
|
|
23522
|
+
probe: async (channel) => {
|
|
23523
|
+
try {
|
|
23524
|
+
await this.getInfo(channel, {
|
|
23525
|
+
timeoutMs: probeTimeoutMs,
|
|
23526
|
+
tags: ["type", "name"]
|
|
23527
|
+
});
|
|
23528
|
+
return true;
|
|
23529
|
+
} catch {
|
|
23530
|
+
return false;
|
|
23531
|
+
}
|
|
23532
|
+
}
|
|
23533
|
+
});
|
|
23534
|
+
this.logger.debug?.(
|
|
23535
|
+
`[ReolinkBaichuanApi] getNvrChannelsSummary: baichuan resolved ${channels.length} channel(s): [${channels.join(", ")}]`
|
|
23536
|
+
);
|
|
23446
23537
|
}
|
|
23447
23538
|
channels = channels.sort((a, b) => a - b);
|
|
23448
|
-
const support = await this.getSupportInfo().catch(() => {
|
|
23449
|
-
this.logger.error?.(
|
|
23450
|
-
"[ReolinkBaichuanApi] getNvrChannelsSummary: failed to get support info"
|
|
23451
|
-
);
|
|
23452
|
-
});
|
|
23453
23539
|
const truthyNumberLike = (v) => {
|
|
23454
23540
|
if (typeof v === "number") return v > 0;
|
|
23455
23541
|
if (typeof v === "string") {
|