@apocaliss92/nodelink-js 0.4.1 → 0.4.3

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/index.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import { Readable } from 'node:stream';
3
+ import * as net from 'node:net';
4
+ import net__default from 'node:net';
3
5
  import http from 'node:http';
4
- import net from 'node:net';
5
6
 
6
7
  declare const BC_TCP_DEFAULT_PORT = 9000;
7
8
  /** Magic header bytes: `f0 de bc 0a` */
@@ -3308,8 +3309,8 @@ declare class ReolinkCgiApi {
3308
3309
  *
3309
3310
  * Structure:
3310
3311
  * - RTSP server uses ffmpeg -rtsp_flags listen to create RTSP server from stdin
3311
- * - Native stream starts only when at least one client is connected
3312
- * - Native stream stops when no clients are connected
3312
+ * - Native stream starts when the first client needs video (e.g. DESCRIBE/PLAY path)
3313
+ * - Native stream auto-stop when no clients is optional (see nativeStreamIdleStopMs)
3313
3314
  * - Tracks connected clients
3314
3315
  * - Passes native frames directly to ffmpeg without repacketization
3315
3316
  */
@@ -3346,6 +3347,23 @@ interface BaichuanRtspServerOptions {
3346
3347
  * isolating it from other streams on the shared socket (avoids streamType mismatch).
3347
3348
  */
3348
3349
  deviceId?: string;
3350
+ /**
3351
+ * When true, the server does NOT create its own net.Server.
3352
+ * Connections are accepted externally via acceptConnection().
3353
+ * start() still performs metadata fetch and codec detection.
3354
+ */
3355
+ externalListener?: boolean;
3356
+ /**
3357
+ * Ms after the last RTSP client disconnects before stopping the native Baichuan stream.
3358
+ * 0 = keep the native stream running (matches rtsp proxy idle timeout 0 / always-mounted sources).
3359
+ * Default 30000.
3360
+ */
3361
+ nativeStreamIdleStopMs?: number;
3362
+ /**
3363
+ * If the native stream is primed (e.g. DESCRIBE) but no client SETUP/PLAYs, stop after this many ms.
3364
+ * 0 = disable. Default 15000 when nativeStreamIdleStopMs > 0, else 0.
3365
+ */
3366
+ nativeStreamPrimeIdleStopMs?: number;
3349
3367
  }
3350
3368
  /**
3351
3369
  * BaichuanRtspServer - RTSP server that serves a Baichuan video stream.
@@ -3355,8 +3373,8 @@ interface BaichuanRtspServerOptions {
3355
3373
  *
3356
3374
  * Lifecycle:
3357
3375
  * - Server starts immediately (ffmpeg RTSP server)
3358
- * - Native stream starts only when first client connects
3359
- * - Native stream stops when last client disconnects
3376
+ * - Native stream starts when clients need media
3377
+ * - Native stream may stay running with zero RTSP clients if nativeStreamIdleStopMs is 0
3360
3378
  */
3361
3379
  declare class BaichuanRtspServer extends EventEmitter<{
3362
3380
  client: [string];
@@ -3377,6 +3395,7 @@ declare class BaichuanRtspServer extends EventEmitter<{
3377
3395
  private flow;
3378
3396
  private deviceId;
3379
3397
  private dedicatedSessionRelease;
3398
+ private externalListener;
3380
3399
  private authCredentials;
3381
3400
  private requireAuth;
3382
3401
  private authNonces;
@@ -3401,6 +3420,10 @@ declare class BaichuanRtspServer extends EventEmitter<{
3401
3420
  private tempStreamGenerator;
3402
3421
  private nativeFanout;
3403
3422
  private noClientAutoStopTimer;
3423
+ /** After last RTSP client; 0 = never auto-stop native stream. */
3424
+ private readonly nativeStreamIdleStopMs;
3425
+ /** Primed-but-no-PLAY timeout; 0 = disabled. */
3426
+ private readonly nativeStreamPrimeIdleStopMs;
3404
3427
  private readonly PREBUFFER_MAX_MS;
3405
3428
  private prebuffer;
3406
3429
  private static isAdtsAacFrame;
@@ -3441,6 +3464,13 @@ declare class BaichuanRtspServer extends EventEmitter<{
3441
3464
  * Start the RTSP server.
3442
3465
  */
3443
3466
  start(): Promise<void>;
3467
+ /**
3468
+ * Accept an externally-routed RTSP connection.
3469
+ * Used in directHandoff mode where RtspProxyServer routes sockets here.
3470
+ * @param socket - The client TCP socket (already authenticated by proxy)
3471
+ * @param initialBuffer - Any bytes already read during path parsing/auth
3472
+ */
3473
+ acceptConnection(socket: net.Socket, initialBuffer?: Buffer): void;
3444
3474
  /**
3445
3475
  * Handle RTSP connection from a client.
3446
3476
  */
@@ -3493,6 +3523,33 @@ declare class BaichuanRtspServer extends EventEmitter<{
3493
3523
  * Get number of connected clients.
3494
3524
  */
3495
3525
  getClientCount(): number;
3526
+ /**
3527
+ * Subscribe to the raw native stream for diagnostic purposes.
3528
+ * The subscriber receives the same frames as RTSP clients.
3529
+ * Counts as a "consumer" for lifecycle — prevents auto-stop while subscribed.
3530
+ * If the native stream is not active, starts it automatically.
3531
+ */
3532
+ subscribeDiagnostic(id: string): Promise<AsyncGenerator<{
3533
+ audio: boolean;
3534
+ data: Buffer;
3535
+ codec: string | null;
3536
+ sampleRate: number | null;
3537
+ microseconds: number | null;
3538
+ videoType?: "H264" | "H265";
3539
+ }, void, unknown>>;
3540
+ /**
3541
+ * Unsubscribe a diagnostic session.
3542
+ */
3543
+ unsubscribeDiagnostic(id: string): void;
3544
+ /**
3545
+ * Returns detected audio metadata (available after first audio frame).
3546
+ */
3547
+ getAudioInfo(): {
3548
+ codec: "aac-adts";
3549
+ sampleRate: number;
3550
+ channels: number;
3551
+ configHex: string;
3552
+ } | null;
3496
3553
  }
3497
3554
 
3498
3555
  /**
@@ -3926,6 +3983,8 @@ declare function captureModelFixtures(params: {
3926
3983
  outDir: string;
3927
3984
  /** Logger (defaults to console) */
3928
3985
  log?: (...args: unknown[]) => void;
3986
+ /** Skip the stream combination test (useful for NVR channels where the test should be done separately per-camera) */
3987
+ skipStreamCombinationTest?: boolean;
3929
3988
  }): Promise<ModelFixtureCaptureResult>;
3930
3989
 
3931
3990
  /**
@@ -7610,7 +7669,7 @@ declare function packetizeAacRawFrame(raw: Buffer, rtp: RtpWriter): {
7610
7669
  packets: Buffer[];
7611
7670
  };
7612
7671
  interface Rfc4571Client {
7613
- socket: net.Socket;
7672
+ socket: net__default.Socket;
7614
7673
  needsKeyframe: boolean;
7615
7674
  sentVideoConfig: boolean;
7616
7675
  }
@@ -7637,7 +7696,7 @@ declare class Rfc4571Muxer {
7637
7696
  private cachedH264ParamSetsAnnexB;
7638
7697
  private cachedH265ParamSetsAnnexB;
7639
7698
  constructor(logger: Console, videoPayloadType: number, audioPayloadType: number | undefined, videoFpsFallback?: number, maxRtpPayload?: number);
7640
- addClient(socket: net.Socket): void;
7699
+ addClient(socket: net__default.Socket): void;
7641
7700
  private static readonly ANNEXB_START_CODE;
7642
7701
  private static joinAnnexBNals;
7643
7702
  private updateVideoParamSetsFromAccessUnit;
@@ -7759,7 +7818,7 @@ interface Rfc4571TcpServer {
7759
7818
  };
7760
7819
  username: string;
7761
7820
  password: string;
7762
- server: net.Server;
7821
+ server: net__default.Server;
7763
7822
  videoStream: BaichuanVideoStream | CompositeStream;
7764
7823
  close: (reason?: unknown) => Promise<void>;
7765
7824
  }
@@ -7815,7 +7874,7 @@ interface Rfc4571ReplayServer {
7815
7874
  };
7816
7875
  username: string;
7817
7876
  password: string;
7818
- server: net.Server;
7877
+ server: net__default.Server;
7819
7878
  videoStream: BaichuanVideoStream;
7820
7879
  /** Called when replay naturally ends (all data sent). */
7821
7880
  onReplayEnd?: () => void;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import http from 'node:http';
3
- import net from 'node:net';
3
+ import * as net from 'node:net';
4
+ import { default as net_2 } from 'node:net';
4
5
  import { Readable } from 'node:stream';
5
6
 
6
7
  export declare function abilitiesHasAny(abilities: AbilityInfo | undefined, re: RegExp): boolean;
@@ -1269,8 +1270,8 @@ export declare type BaichuanRecordSchedule = {
1269
1270
  *
1270
1271
  * Lifecycle:
1271
1272
  * - Server starts immediately (ffmpeg RTSP server)
1272
- * - Native stream starts only when first client connects
1273
- * - Native stream stops when last client disconnects
1273
+ * - Native stream starts when clients need media
1274
+ * - Native stream may stay running with zero RTSP clients if nativeStreamIdleStopMs is 0
1274
1275
  */
1275
1276
  export declare class BaichuanRtspServer extends EventEmitter<{
1276
1277
  client: [string];
@@ -1291,6 +1292,7 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1291
1292
  private flow;
1292
1293
  private deviceId;
1293
1294
  private dedicatedSessionRelease;
1295
+ private externalListener;
1294
1296
  private authCredentials;
1295
1297
  private requireAuth;
1296
1298
  private authNonces;
@@ -1315,6 +1317,10 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1315
1317
  private tempStreamGenerator;
1316
1318
  private nativeFanout;
1317
1319
  private noClientAutoStopTimer;
1320
+ /** After last RTSP client; 0 = never auto-stop native stream. */
1321
+ private readonly nativeStreamIdleStopMs;
1322
+ /** Primed-but-no-PLAY timeout; 0 = disabled. */
1323
+ private readonly nativeStreamPrimeIdleStopMs;
1318
1324
  private readonly PREBUFFER_MAX_MS;
1319
1325
  private prebuffer;
1320
1326
  private static isAdtsAacFrame;
@@ -1355,6 +1361,13 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1355
1361
  * Start the RTSP server.
1356
1362
  */
1357
1363
  start(): Promise<void>;
1364
+ /**
1365
+ * Accept an externally-routed RTSP connection.
1366
+ * Used in directHandoff mode where RtspProxyServer routes sockets here.
1367
+ * @param socket - The client TCP socket (already authenticated by proxy)
1368
+ * @param initialBuffer - Any bytes already read during path parsing/auth
1369
+ */
1370
+ acceptConnection(socket: net.Socket, initialBuffer?: Buffer): void;
1358
1371
  /**
1359
1372
  * Handle RTSP connection from a client.
1360
1373
  */
@@ -1407,6 +1420,33 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1407
1420
  * Get number of connected clients.
1408
1421
  */
1409
1422
  getClientCount(): number;
1423
+ /**
1424
+ * Subscribe to the raw native stream for diagnostic purposes.
1425
+ * The subscriber receives the same frames as RTSP clients.
1426
+ * Counts as a "consumer" for lifecycle — prevents auto-stop while subscribed.
1427
+ * If the native stream is not active, starts it automatically.
1428
+ */
1429
+ subscribeDiagnostic(id: string): Promise<AsyncGenerator<{
1430
+ audio: boolean;
1431
+ data: Buffer;
1432
+ codec: string | null;
1433
+ sampleRate: number | null;
1434
+ microseconds: number | null;
1435
+ videoType?: "H264" | "H265";
1436
+ }, void, unknown>>;
1437
+ /**
1438
+ * Unsubscribe a diagnostic session.
1439
+ */
1440
+ unsubscribeDiagnostic(id: string): void;
1441
+ /**
1442
+ * Returns detected audio metadata (available after first audio frame).
1443
+ */
1444
+ getAudioInfo(): {
1445
+ codec: "aac-adts";
1446
+ sampleRate: number;
1447
+ channels: number;
1448
+ configHex: string;
1449
+ } | null;
1410
1450
  }
1411
1451
 
1412
1452
  export declare interface BaichuanRtspServerOptions {
@@ -1441,6 +1481,23 @@ export declare interface BaichuanRtspServerOptions {
1441
1481
  * isolating it from other streams on the shared socket (avoids streamType mismatch).
1442
1482
  */
1443
1483
  deviceId?: string;
1484
+ /**
1485
+ * When true, the server does NOT create its own net.Server.
1486
+ * Connections are accepted externally via acceptConnection().
1487
+ * start() still performs metadata fetch and codec detection.
1488
+ */
1489
+ externalListener?: boolean;
1490
+ /**
1491
+ * Ms after the last RTSP client disconnects before stopping the native Baichuan stream.
1492
+ * 0 = keep the native stream running (matches rtsp proxy idle timeout 0 / always-mounted sources).
1493
+ * Default 30000.
1494
+ */
1495
+ nativeStreamIdleStopMs?: number;
1496
+ /**
1497
+ * If the native stream is primed (e.g. DESCRIBE) but no client SETUP/PLAYs, stop after this many ms.
1498
+ * 0 = disable. Default 15000 when nativeStreamIdleStopMs > 0, else 0.
1499
+ */
1500
+ nativeStreamPrimeIdleStopMs?: number;
1444
1501
  }
1445
1502
 
1446
1503
  export declare type BaichuanSerialPush = {
@@ -2520,6 +2577,8 @@ export declare function captureModelFixtures(params: {
2520
2577
  outDir: string;
2521
2578
  /** Logger (defaults to console) */
2522
2579
  log?: (...args: unknown[]) => void;
2580
+ /** Skip the stream combination test (useful for NVR channels where the test should be done separately per-camera) */
2581
+ skipStreamCombinationTest?: boolean;
2523
2582
  }): Promise<ModelFixtureCaptureResult>;
2524
2583
 
2525
2584
  export declare type CgiAbility = {
@@ -8409,7 +8468,7 @@ export declare interface Rfc4571ApiFactoryContext {
8409
8468
  }
8410
8469
 
8411
8470
  export declare interface Rfc4571Client {
8412
- socket: net.Socket;
8471
+ socket: net_2.Socket;
8413
8472
  needsKeyframe: boolean;
8414
8473
  sentVideoConfig: boolean;
8415
8474
  }
@@ -8437,7 +8496,7 @@ export declare class Rfc4571Muxer {
8437
8496
  private cachedH264ParamSetsAnnexB;
8438
8497
  private cachedH265ParamSetsAnnexB;
8439
8498
  constructor(logger: Console, videoPayloadType: number, audioPayloadType: number | undefined, videoFpsFallback?: number, maxRtpPayload?: number);
8440
- addClient(socket: net.Socket): void;
8499
+ addClient(socket: net_2.Socket): void;
8441
8500
  private static readonly ANNEXB_START_CODE;
8442
8501
  private static joinAnnexBNals;
8443
8502
  private updateVideoParamSetsFromAccessUnit;
@@ -8477,7 +8536,7 @@ export declare interface Rfc4571ReplayServer {
8477
8536
  };
8478
8537
  username: string;
8479
8538
  password: string;
8480
- server: net.Server;
8539
+ server: net_2.Server;
8481
8540
  videoStream: BaichuanVideoStream;
8482
8541
  /** Called when replay naturally ends (all data sent). */
8483
8542
  onReplayEnd?: () => void;
@@ -8536,7 +8595,7 @@ export declare interface Rfc4571TcpServer {
8536
8595
  };
8537
8596
  username: string;
8538
8597
  password: string;
8539
- server: net.Server;
8598
+ server: net_2.Server;
8540
8599
  videoStream: BaichuanVideoStream | CompositeStream;
8541
8600
  close: (reason?: unknown) => Promise<void>;
8542
8601
  }
package/dist/index.js CHANGED
@@ -43,7 +43,7 @@ import {
43
43
  parseSupportXml,
44
44
  setGlobalLogger,
45
45
  xmlIndicatesFloodlight
46
- } from "./chunk-SDRNJQ5U.js";
46
+ } from "./chunk-UHFJPQA4.js";
47
47
  import {
48
48
  AesStreamDecryptor,
49
49
  BC_AES_IV,
@@ -223,7 +223,7 @@ import {
223
223
  testChannelStreams,
224
224
  xmlEscape,
225
225
  zipDirectory
226
- } from "./chunk-DUHWTZ7U.js";
226
+ } from "./chunk-DEOMUWBN.js";
227
227
 
228
228
  // src/reolink/baichuan/HlsSessionManager.ts
229
229
  var withTimeout = async (p, ms, label) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apocaliss92/nodelink-js",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "TypeScript library implementing Reolink Baichuan protocol (control + streaming) with CGI and RTSP helpers. Full TypeScript support with comprehensive type definitions.",
5
5
  "license": "MIT",
6
6
  "author": "",