@apocaliss92/nodelink-js 0.4.7 → 0.4.10

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.ts CHANGED
@@ -179,6 +179,25 @@ export declare type AiTypesCacheEntry = {
179
179
 
180
180
  export declare type AnyBuffer = Buffer<ArrayBufferLike>;
181
181
 
182
+ /**
183
+ * Patch one or more fields inside an `<Enc>` stream block
184
+ * (`<mainStream>` or `<subStream>`). Used by `setEnc` —
185
+ * Reolink emits both blocks in the same document so a per-block scope
186
+ * is needed to avoid clobbering the wrong stream.
187
+ */
188
+ export declare function applyStreamPatch(xml: string, streamTag: "mainStream" | "subStream", patch: {
189
+ bitRate?: number;
190
+ frameRate?: number;
191
+ videoEncType?: "h264" | "h265";
192
+ } | undefined): string;
193
+
194
+ /**
195
+ * Replace the text content of `<tag>...</tag>` (first match) with the
196
+ * stringified value. No-op when `value` is undefined — lets callers
197
+ * pass partial patches without branching at every field.
198
+ */
199
+ export declare function applyXmlTagPatch(xml: string, tag: string, value: string | number | boolean | undefined): string;
200
+
182
201
  export declare function asLogger(logger?: LoggerLike): Logger_2;
183
202
 
184
203
  export declare interface AudioAlarmParams {
@@ -218,6 +237,22 @@ export declare type AudioConfig = {
218
237
  channels: number;
219
238
  };
220
239
 
240
+ /**
241
+ * Audio noise reduction configuration (`getAudioNoise`).
242
+ * cmdId=439. Note: the wire tag is lowercase `aiDenoise` (capital `V`
243
+ * in `@_Version`). Mirrors the camera-side schema observed live.
244
+ */
245
+ export declare interface AudioNoiseConfig {
246
+ body?: {
247
+ aiDenoise?: {
248
+ channelId?: number | undefined;
249
+ enable?: number | undefined;
250
+ level?: number | undefined;
251
+ [key: string]: unknown;
252
+ };
253
+ };
254
+ }
255
+
221
256
  /**
222
257
  * AudioTask configuration - controls siren/alarm on motion detection.
223
258
  * Retrieved via cmdId=232 (GET) and set via cmdId=231 (SET).
@@ -383,6 +418,23 @@ export declare interface AutodiscoveryClientOptions extends DiscoveryOptions {
383
418
  onDeviceUpdated?: (device: DiscoveredDevice) => void;
384
419
  }
385
420
 
421
+ /**
422
+ * Auto-focus configuration (`getAutoFocus`). cmdId=224.
423
+ *
424
+ * The `disable` field is a 0/1 flag — `0` means autofocus is ENABLED.
425
+ * Non-PTZ cameras may return an empty `{}` or 400 — callers should
426
+ * narrow `body?.AutoFocus?.disable` defensively.
427
+ */
428
+ export declare interface AutoFocusConfig {
429
+ body?: {
430
+ AutoFocus?: {
431
+ channelId?: number | undefined;
432
+ disable?: number | undefined;
433
+ [key: string]: unknown;
434
+ };
435
+ };
436
+ }
437
+
386
438
  export declare type BaichuanCachedPush<T> = {
387
439
  updatedAtMs: number;
388
440
  value: T;
@@ -1311,6 +1363,7 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1311
1363
  private authNonces;
1312
1364
  private readonly AUTH_REALM;
1313
1365
  private readonly NONCE_TIMEOUT_MS;
1366
+ private readonly lazyMetadata;
1314
1367
  private connectedClients;
1315
1368
  private nativeStreamActive;
1316
1369
  private clientConnectionServer;
@@ -1330,10 +1383,20 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1330
1383
  private tempStreamGenerator;
1331
1384
  private nativeFanout;
1332
1385
  private noClientAutoStopTimer;
1386
+ /** Fires if camera never sends frames after stream start (sleeping), even with clients connected. */
1387
+ private noFrameDeadlineTimer;
1333
1388
  /** After last RTSP client; 0 = never auto-stop native stream. */
1334
1389
  private readonly nativeStreamIdleStopMs;
1335
1390
  /** Primed-but-no-PLAY timeout; 0 = disabled. */
1336
1391
  private readonly nativeStreamPrimeIdleStopMs;
1392
+ /**
1393
+ * Max time to wait for the first camera frame after stream start.
1394
+ * If no frames arrive within this window, the native stream is stopped
1395
+ * (camera is sleeping). Prevents the BaichuanVideoStream watchdog from
1396
+ * firing and waking the camera when no real viewer is watching.
1397
+ * 0 = disabled. Defaults to nativeStreamPrimeIdleStopMs * 2 when > 0.
1398
+ */
1399
+ private readonly nativeStreamNoFrameDeadlineMs;
1337
1400
  private readonly PREBUFFER_MAX_MS;
1338
1401
  private prebuffer;
1339
1402
  private static isAdtsAacFrame;
@@ -1344,6 +1407,8 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1344
1407
  private static splitAnnexBNals;
1345
1408
  private static stripAdtsHeader;
1346
1409
  constructor(options: BaichuanRtspServerOptions);
1410
+ /** Number of currently connected RTSP clients. */
1411
+ get clientCount(): number;
1347
1412
  /**
1348
1413
  * Generate a new nonce for Digest authentication
1349
1414
  */
@@ -1369,6 +1434,7 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1369
1434
  */
1370
1435
  private generateWwwAuthenticateHeader;
1371
1436
  private clearNoClientAutoStopTimer;
1437
+ private clearNoFrameDeadlineTimer;
1372
1438
  private setFlowVideoType;
1373
1439
  /**
1374
1440
  * Start the RTSP server.
@@ -1381,6 +1447,21 @@ export declare class BaichuanRtspServer extends EventEmitter<{
1381
1447
  * @param initialBuffer - Any bytes already read during path parsing/auth
1382
1448
  */
1383
1449
  acceptConnection(socket: net.Socket, initialBuffer?: Buffer): void;
1450
+ /**
1451
+ * Inject an already-accepted client socket from a multiplexer
1452
+ * (e.g. `LocalRtspMux`) that owns the listening port.
1453
+ *
1454
+ * The mux reads the first RTSP request line to determine the target path,
1455
+ * then hands the socket over. Any bytes already consumed during routing
1456
+ * are replayed back onto the socket via `unshift()` so the RTSP parser in
1457
+ * `handleRtspConnection` sees the complete original request.
1458
+ *
1459
+ * @param socket - Client TCP socket, already accepted by the mux.
1460
+ * @param preReadData - Bytes the mux has already pulled off the socket
1461
+ * while parsing the request line. Replayed via `socket.unshift()`
1462
+ * before any further reads.
1463
+ */
1464
+ injectSocket(socket: net.Socket, preReadData: Buffer): void;
1384
1465
  /**
1385
1466
  * Handle RTSP connection from a client.
1386
1467
  */
@@ -1481,13 +1562,34 @@ export declare interface BaichuanRtspServerOptions {
1481
1562
  * - "rfc4571": RFC4571 framing: 2-byte length + RTP packet
1482
1563
  */
1483
1564
  tcpRtpFraming?: "rtsp-interleaved" | "rfc4571";
1484
- /** Credentials for RTSP authentication (optional) */
1565
+ /**
1566
+ * Credentials for RTSP authentication (optional).
1567
+ *
1568
+ * Each entry carries either the plaintext `password` or a pre-computed
1569
+ * Digest `ha1 = MD5(username ":" realm ":" password)`. The HA1 variant is
1570
+ * preferred when the consumer stores only hashed credentials (e.g. the
1571
+ * manager reuses dashboard-user HA1 values without ever holding plaintext).
1572
+ *
1573
+ * When both are supplied, `ha1` wins for Digest validation while `password`
1574
+ * is used for Basic authentication.
1575
+ */
1485
1576
  credentials?: Array<{
1486
1577
  username: string;
1487
1578
  password: string;
1579
+ ha1?: string;
1580
+ } | {
1581
+ username: string;
1582
+ password?: string;
1583
+ ha1: string;
1488
1584
  }>;
1489
1585
  /** Require authentication for RTSP connections (default: false if no credentials set) */
1490
1586
  requireAuth?: boolean;
1587
+ /**
1588
+ * Digest authentication realm advertised to clients. Must match the realm
1589
+ * used when pre-computing HA1 values in `credentials[*].ha1`.
1590
+ * Default: "BaichuanRtspServer" (kept for backward compatibility).
1591
+ */
1592
+ authRealm?: string;
1491
1593
  /**
1492
1594
  * External identifier for dedicated socket session.
1493
1595
  * When provided, a dedicated BaichuanClient is created for the stream,
@@ -1500,6 +1602,18 @@ export declare interface BaichuanRtspServerOptions {
1500
1602
  * start() still performs metadata fetch and codec detection.
1501
1603
  */
1502
1604
  externalListener?: boolean;
1605
+ /**
1606
+ * When true, the server runs in **mux mode**: `start()` skips creating
1607
+ * or listening on any TCP server (a shared multiplexer — e.g.
1608
+ * `LocalRtspMux` — owns the public RTSP port and routes accepted sockets
1609
+ * here via `injectSocket()`). `stop()` likewise skips closing a TCP
1610
+ * server it does not own.
1611
+ *
1612
+ * Semantically equivalent to `externalListener: true`, but expressed from
1613
+ * the point of view of the multiplexer that will drive this instance.
1614
+ * Either flag is sufficient; both may be set together.
1615
+ */
1616
+ muxMode?: boolean;
1503
1617
  /**
1504
1618
  * Ms after the last RTSP client disconnects before stopping the native Baichuan stream.
1505
1619
  * 0 = keep the native stream running (matches rtsp proxy idle timeout 0 / always-mounted sources).
@@ -1511,6 +1625,18 @@ export declare interface BaichuanRtspServerOptions {
1511
1625
  * 0 = disable. Default 15000 when nativeStreamIdleStopMs > 0, else 0.
1512
1626
  */
1513
1627
  nativeStreamPrimeIdleStopMs?: number;
1628
+ /**
1629
+ * When true, `start()` does NOT fetch stream metadata from the camera —
1630
+ * the metadata fetch is deferred to the first DESCRIBE. Useful for
1631
+ * battery / UDP cameras so binding the RTSP port at boot does not wake
1632
+ * them up when no client is listening.
1633
+ *
1634
+ * Trade-off: the very first DESCRIBE pays the metadata round-trip
1635
+ * latency. Subsequent connections hit the cached metadata.
1636
+ *
1637
+ * Default: false (keep existing behaviour).
1638
+ */
1639
+ lazyMetadata?: boolean;
1514
1640
  }
1515
1641
 
1516
1642
  export declare type BaichuanSerialPush = {
@@ -1899,12 +2025,16 @@ export declare const BC_CMD_ID_AUDIO_ALARM_PLAY = 263;
1899
2025
 
1900
2026
  export declare const BC_CMD_ID_CHANNEL_INFO_ALL = 145;
1901
2027
 
2028
+ /** @deprecated Use {@link BC_CMD_ID_SET_LED_STATE} (209). */
1902
2029
  export declare const BC_CMD_ID_CMD_123 = 123;
1903
2030
 
2031
+ /** @deprecated Use {@link BC_CMD_ID_SET_LED_STATE} (209). */
1904
2032
  export declare const BC_CMD_ID_CMD_209 = 209;
1905
2033
 
2034
+ /** @deprecated Use {@link BC_CMD_ID_SET_AUDIO_CFG} (265). */
1906
2035
  export declare const BC_CMD_ID_CMD_265 = 265;
1907
2036
 
2037
+ /** @deprecated Use {@link BC_CMD_ID_SET_AI_DENOISE} (440). */
1908
2038
  export declare const BC_CMD_ID_CMD_440 = 440;
1909
2039
 
1910
2040
  export declare const BC_CMD_ID_COVER_PREVIEW = 298;
@@ -1963,6 +2093,8 @@ export declare const BC_CMD_ID_GET_AUDIO_CFG = 264;
1963
2093
 
1964
2094
  export declare const BC_CMD_ID_GET_AUDIO_TASK = 232;
1965
2095
 
2096
+ export declare const BC_CMD_ID_GET_AUTO_FOCUS = 224;
2097
+
1966
2098
  export declare const BC_CMD_ID_GET_BATTERY_INFO = 253;
1967
2099
 
1968
2100
  export declare const BC_CMD_ID_GET_BATTERY_INFO_LIST = 252;
@@ -1979,6 +2111,8 @@ export declare const BC_CMD_ID_GET_DING_DONG_SILENT = 609;
1979
2111
 
1980
2112
  export declare const BC_CMD_ID_GET_EMAIL_TASK = 217;
1981
2113
 
2114
+ export declare const BC_CMD_ID_GET_ENC = 56;
2115
+
1982
2116
  export declare const BC_CMD_ID_GET_FTP_TASK = 70;
1983
2117
 
1984
2118
  export declare const BC_CMD_ID_GET_HDD_INFO_LIST = 102;
@@ -1995,10 +2129,14 @@ export declare const BC_CMD_ID_GET_OSD_DATETIME = 44;
1995
2129
 
1996
2130
  export declare const BC_CMD_ID_GET_PIR_INFO = 212;
1997
2131
 
2132
+ export declare const BC_CMD_ID_GET_PRIVACY_MASK = 52;
2133
+
1998
2134
  export declare const BC_CMD_ID_GET_PTZ_POSITION = 433;
1999
2135
 
2000
2136
  export declare const BC_CMD_ID_GET_PTZ_PRESET = 190;
2001
2137
 
2138
+ export declare const BC_CMD_ID_GET_PUSH_TASK = 219;
2139
+
2002
2140
  export declare const BC_CMD_ID_GET_REC_ENC_CFG = 507;
2003
2141
 
2004
2142
  export declare const BC_CMD_ID_GET_RECORD = 81;
@@ -2062,16 +2200,40 @@ export declare const BC_CMD_ID_SET_AI_ALARM = 343;
2062
2200
 
2063
2201
  export declare const BC_CMD_ID_SET_AI_CFG = 300;
2064
2202
 
2203
+ export declare const BC_CMD_ID_SET_AI_DENOISE = 440;
2204
+
2205
+ export declare const BC_CMD_ID_SET_AUDIO_CFG = 265;
2206
+
2065
2207
  export declare const BC_CMD_ID_SET_AUDIO_TASK = 231;
2066
2208
 
2209
+ export declare const BC_CMD_ID_SET_AUTO_FOCUS = 225;
2210
+
2211
+ export declare const BC_CMD_ID_SET_DAY_NIGHT_THRESHOLD = 297;
2212
+
2067
2213
  export declare const BC_CMD_ID_SET_DING_DONG_CFG = 487;
2068
2214
 
2069
2215
  export declare const BC_CMD_ID_SET_DING_DONG_SILENT = 610;
2070
2216
 
2217
+ export declare const BC_CMD_ID_SET_EMAIL_TASK = 216;
2218
+
2219
+ export declare const BC_CMD_ID_SET_ENC = 57;
2220
+
2221
+ export declare const BC_CMD_ID_SET_LED_STATE = 209;
2222
+
2071
2223
  export declare const BC_CMD_ID_SET_MOTION_ALARM = 47;
2072
2224
 
2073
2225
  export declare const BC_CMD_ID_SET_PIR_INFO = 213;
2074
2226
 
2227
+ export declare const BC_CMD_ID_SET_PRIVACY_MASK = 53;
2228
+
2229
+ export declare const BC_CMD_ID_SET_PUSH_TASK = 218;
2230
+
2231
+ export declare const BC_CMD_ID_SET_RECORD = 82;
2232
+
2233
+ export declare const BC_CMD_ID_SET_RECORD_CFG = 55;
2234
+
2235
+ export declare const BC_CMD_ID_SET_VIDEO_INPUT = 25;
2236
+
2075
2237
  export declare const BC_CMD_ID_SET_WHITE_LED_STATE = 288;
2076
2238
 
2077
2239
  export declare const BC_CMD_ID_SET_WHITE_LED_TASK = 290;
@@ -2734,12 +2896,42 @@ export declare type CgiAbilityLeaf = {
2734
2896
  ver: number;
2735
2897
  };
2736
2898
 
2899
+ export declare type CgiAiAlarm = {
2900
+ channel: number;
2901
+ ai_type: string;
2902
+ sensitivity?: number;
2903
+ stayTime?: number;
2904
+ } & Record<string, JsonValue>;
2905
+
2906
+ export declare type CgiAiCfg = {
2907
+ channel: number;
2908
+ AiTrack?: number;
2909
+ smartTrack?: number;
2910
+ trackType?: Record<string, number>;
2911
+ } & Record<string, JsonValue>;
2912
+
2737
2913
  export declare type CgiAiKey = "dog_cat" | "face" | "other" | "package" | "people" | "vehicle";
2738
2914
 
2739
2915
  export declare type CgiAiStateValue = Partial<Record<CgiAiKey, CgiDetectionState>> & {
2740
2916
  channel: number;
2741
2917
  };
2742
2918
 
2919
+ export declare type CgiAudioAlarm = {
2920
+ schedule?: {
2921
+ channel?: number;
2922
+ enable?: number;
2923
+ table?: string;
2924
+ };
2925
+ scheduleEnable?: number;
2926
+ enable?: number;
2927
+ /** Built-in audio id; varies by camera. Use AudioAlarmPlay for
2928
+ * one-shot test playback. */
2929
+ audioId?: number;
2930
+ /** Times to repeat the audio per trigger. */
2931
+ alarmTimes?: number;
2932
+ audioVolume?: number;
2933
+ } & Record<string, JsonValue>;
2934
+
2743
2935
  export declare type CgiAudioAlarmPlayParam = ({
2744
2936
  channel: number;
2745
2937
  } & {
@@ -2752,6 +2944,28 @@ export declare type CgiAudioAlarmPlayParam = ({
2752
2944
  manual_switch: number;
2753
2945
  });
2754
2946
 
2947
+ export declare type CgiAudioCfg = {
2948
+ channel: number;
2949
+ /** 0 = unmuted, 1 = muted. */
2950
+ mute?: number;
2951
+ /** 0..100. */
2952
+ volume?: number;
2953
+ } & Record<string, JsonValue>;
2954
+
2955
+ export declare type CgiAudioNoise = {
2956
+ channel: number;
2957
+ enable?: number;
2958
+ /** 0 = disabled, 1..N = strength tier (model-specific). */
2959
+ level?: number;
2960
+ } & Record<string, JsonValue>;
2961
+
2962
+ export declare type CgiAutoFocus = {
2963
+ channel: number;
2964
+ /** 0 = enabled (default), 1 = disabled. Reolink names it `disable`
2965
+ * rather than `enable` because AF is on by default. */
2966
+ disable?: number;
2967
+ } & Record<string, JsonValue>;
2968
+
2755
2969
  export declare type CgiBattery = {
2756
2970
  batteryPercent?: number;
2757
2971
  } & Record<string, JsonValue>;
@@ -2805,6 +3019,29 @@ export declare type CgiDevInfo = {
2805
3019
  wifi?: number;
2806
3020
  };
2807
3021
 
3022
+ export declare type CgiEmail = {
3023
+ schedule?: {
3024
+ channel?: number;
3025
+ enable?: number;
3026
+ table?: string;
3027
+ };
3028
+ scheduleEnable?: number;
3029
+ enable?: number;
3030
+ smtpServer?: string;
3031
+ smtpPort?: number;
3032
+ userName?: string;
3033
+ password?: string;
3034
+ addr1?: string;
3035
+ addr2?: string;
3036
+ addr3?: string;
3037
+ ssl?: number;
3038
+ attachment?: number;
3039
+ interval?: string;
3040
+ textType?: string;
3041
+ subject?: string;
3042
+ content?: string;
3043
+ } & Record<string, JsonValue>;
3044
+
2808
3045
  export declare type CgiEnc = {
2809
3046
  audio: number;
2810
3047
  channel: number;
@@ -2833,10 +3070,34 @@ export declare type CgiGetAbilityResponse = ReolinkCmdResponseExt<CgiGetAbilityV
2833
3070
 
2834
3071
  export declare type CgiGetAbilityValue = CgiAbility;
2835
3072
 
3073
+ export declare type CgiGetAiAlarmValue = {
3074
+ AiAlarm?: CgiAiAlarm;
3075
+ } & Record<string, JsonValue>;
3076
+
3077
+ export declare type CgiGetAiCfgValue = {
3078
+ AiCfg?: CgiAiCfg;
3079
+ } & Record<string, JsonValue>;
3080
+
2836
3081
  export declare type CgiGetAiStateResponse = ReolinkCmdResponseExt<CgiAiStateValue> & {
2837
3082
  cmd: "GetAiState";
2838
3083
  };
2839
3084
 
3085
+ export declare type CgiGetAudioAlarmValue = {
3086
+ Audio?: CgiAudioAlarm;
3087
+ } & Record<string, JsonValue>;
3088
+
3089
+ export declare type CgiGetAudioCfgValue = {
3090
+ AudioCfg?: CgiAudioCfg;
3091
+ } & Record<string, JsonValue>;
3092
+
3093
+ export declare type CgiGetAudioNoiseValue = {
3094
+ AudioNoise?: CgiAudioNoise;
3095
+ } & Record<string, JsonValue>;
3096
+
3097
+ export declare type CgiGetAutoFocusValue = {
3098
+ AutoFocus?: CgiAutoFocus;
3099
+ } & Record<string, JsonValue>;
3100
+
2840
3101
  export declare type CgiGetChannelstatusResponse = ReolinkCmdResponseExt<CgiGetChannelstatusValue> & {
2841
3102
  cmd: "GetChannelstatus";
2842
3103
  };
@@ -2857,16 +3118,48 @@ export declare type CgiGetDevInfoValue = {
2857
3118
  DevInfo: CgiDevInfo;
2858
3119
  };
2859
3120
 
3121
+ export declare type CgiGetEmailValue = {
3122
+ Email?: CgiEmail;
3123
+ } & Record<string, JsonValue>;
3124
+
2860
3125
  export declare type CgiGetEncResponse = ReolinkCmdResponseExt<CgiEncValue> & {
2861
3126
  cmd: "GetEnc";
2862
3127
  initial?: CgiEncValue;
2863
3128
  range?: JsonValue;
2864
3129
  };
2865
3130
 
3131
+ export declare type CgiGetImageValue = {
3132
+ Image?: CgiImage;
3133
+ } & Record<string, JsonValue>;
3134
+
3135
+ export declare type CgiGetIrLightsValue = {
3136
+ IrLights?: CgiIrLights;
3137
+ } & Record<string, JsonValue>;
3138
+
3139
+ export declare type CgiGetIspValue = {
3140
+ Isp?: CgiIsp;
3141
+ } & Record<string, JsonValue>;
3142
+
3143
+ export declare type CgiGetMaskValue = {
3144
+ Mask?: CgiMask;
3145
+ } & Record<string, JsonValue>;
3146
+
3147
+ export declare type CgiGetMdAlarmValue = {
3148
+ MdAlarm?: CgiMdAlarm;
3149
+ } & Record<string, JsonValue>;
3150
+
2866
3151
  export declare type CgiGetOsdValue = {
2867
3152
  Osd?: CgiOsd;
2868
3153
  } & Record<string, JsonValue>;
2869
3154
 
3155
+ export declare type CgiGetPushValue = {
3156
+ Push?: CgiPush;
3157
+ } & Record<string, JsonValue>;
3158
+
3159
+ export declare type CgiGetRecValue = {
3160
+ Rec?: CgiRec;
3161
+ } & Record<string, JsonValue>;
3162
+
2870
3163
  export declare type CgiGetRtspUrlResponse = ReolinkCmdResponseExt<CgiGetRtspUrlValue> & {
2871
3164
  cmd: "GetRtspUrl";
2872
3165
  };
@@ -2907,6 +3200,81 @@ export declare interface CgiGetVideoclipsParams {
2907
3200
  streamUrlType?: "FLV" | "RTMP" | "Playback";
2908
3201
  }
2909
3202
 
3203
+ export declare type CgiImage = {
3204
+ channel: number;
3205
+ bright?: number;
3206
+ contrast?: number;
3207
+ saturation?: number;
3208
+ hue?: number;
3209
+ sharpen?: number;
3210
+ mirroring?: number;
3211
+ flip?: number;
3212
+ } & Record<string, JsonValue>;
3213
+
3214
+ export declare type CgiIrLights = {
3215
+ channel: number;
3216
+ /** "Auto" | "Off" — modern firmwares; some legacy support "On". */
3217
+ state?: string;
3218
+ } & Record<string, JsonValue>;
3219
+
3220
+ export declare type CgiIsp = {
3221
+ channel: number;
3222
+ bright?: number;
3223
+ contrast?: number;
3224
+ saturation?: number;
3225
+ sharpen?: number;
3226
+ hue?: number;
3227
+ antiFlicker?: string;
3228
+ exposure?: string;
3229
+ dayNight?: string;
3230
+ backLight?: string;
3231
+ blueGain?: number;
3232
+ redGain?: number;
3233
+ whiteBalance?: string;
3234
+ mirroring?: number;
3235
+ flip?: number;
3236
+ rotation?: number;
3237
+ } & Record<string, JsonValue>;
3238
+
3239
+ export declare type CgiMask = {
3240
+ channel: number;
3241
+ enable?: number;
3242
+ shelterList?: CgiMaskShelter[];
3243
+ } & Record<string, JsonValue>;
3244
+
3245
+ export declare type CgiMaskShelter = {
3246
+ enabled?: number;
3247
+ position?: {
3248
+ x?: number;
3249
+ y?: number;
3250
+ w?: number;
3251
+ h?: number;
3252
+ };
3253
+ } & Record<string, JsonValue>;
3254
+
3255
+ export declare type CgiMdAlarm = {
3256
+ channel: number;
3257
+ type?: string;
3258
+ enable?: number;
3259
+ scope?: CgiMdAlarmScope;
3260
+ sens?: CgiMdAlarmSens[];
3261
+ } & Record<string, JsonValue>;
3262
+
3263
+ export declare type CgiMdAlarmScope = {
3264
+ cols?: number;
3265
+ rows?: number;
3266
+ table?: string;
3267
+ } & Record<string, JsonValue>;
3268
+
3269
+ export declare type CgiMdAlarmSens = {
3270
+ id?: number;
3271
+ beginHour?: number;
3272
+ beginMin?: number;
3273
+ endHour?: number;
3274
+ endMin?: number;
3275
+ sensitivity?: number;
3276
+ } & Record<string, JsonValue>;
3277
+
2910
3278
  export declare type CgiNetPort = Record<string, JsonValue>;
2911
3279
 
2912
3280
  export declare type CgiOsd = {
@@ -2924,6 +3292,83 @@ export declare type CgiPtzPreset = {
2924
3292
  enable?: number;
2925
3293
  } & Record<string, JsonValue>;
2926
3294
 
3295
+ export declare type CgiPush = {
3296
+ schedule?: {
3297
+ channel?: number;
3298
+ enable?: number;
3299
+ table?: string;
3300
+ };
3301
+ scheduleEnable?: number;
3302
+ enable?: number;
3303
+ } & Record<string, JsonValue>;
3304
+
3305
+ export declare type CgiRec = {
3306
+ schedule?: CgiRecSchedule;
3307
+ scheduleEnable?: number;
3308
+ enable?: number;
3309
+ packTime?: string;
3310
+ postRec?: string;
3311
+ } & Record<string, JsonValue>;
3312
+
3313
+ export declare type CgiRecSchedule = {
3314
+ channel: number;
3315
+ enable?: number;
3316
+ /** 7×24 weekly schedule mask, "1"/"0" per slot — present on V20+. */
3317
+ table?: string;
3318
+ } & Record<string, JsonValue>;
3319
+
3320
+ export declare type CgiSetAiAlarmParam = {
3321
+ AiAlarm: CgiAiAlarm;
3322
+ };
3323
+
3324
+ export declare type CgiSetAiCfgParam = {
3325
+ AiCfg: CgiAiCfg;
3326
+ };
3327
+
3328
+ export declare type CgiSetAudioAlarmParam = {
3329
+ Audio: CgiAudioAlarm;
3330
+ };
3331
+
3332
+ export declare type CgiSetAudioCfgParam = {
3333
+ AudioCfg: CgiAudioCfg;
3334
+ };
3335
+
3336
+ export declare type CgiSetAudioNoiseParam = {
3337
+ AudioNoise: CgiAudioNoise;
3338
+ };
3339
+
3340
+ export declare type CgiSetAutoFocusParam = {
3341
+ AutoFocus: CgiAutoFocus;
3342
+ };
3343
+
3344
+ export declare type CgiSetEmailParam = {
3345
+ Email: CgiEmail;
3346
+ };
3347
+
3348
+ export declare type CgiSetEncParam = {
3349
+ Enc: CgiEnc;
3350
+ };
3351
+
3352
+ export declare type CgiSetImageParam = {
3353
+ Image: CgiImage;
3354
+ };
3355
+
3356
+ export declare type CgiSetIrLightsParam = {
3357
+ IrLights: CgiIrLights;
3358
+ };
3359
+
3360
+ export declare type CgiSetIspParam = {
3361
+ Isp: CgiIsp;
3362
+ };
3363
+
3364
+ export declare type CgiSetMaskParam = {
3365
+ Mask: CgiMask;
3366
+ };
3367
+
3368
+ export declare type CgiSetMdAlarmParam = {
3369
+ MdAlarm: CgiMdAlarm;
3370
+ };
3371
+
2927
3372
  export declare type CgiSetOsdParam = {
2928
3373
  Osd: {
2929
3374
  channel: number;
@@ -2936,6 +3381,14 @@ export declare type CgiSetPirInfoParam = {
2936
3381
  pirInfo: CgiPirInfo;
2937
3382
  };
2938
3383
 
3384
+ export declare type CgiSetPushParam = {
3385
+ Push: CgiPush;
3386
+ };
3387
+
3388
+ export declare type CgiSetRecParam = {
3389
+ Rec: CgiRec;
3390
+ };
3391
+
2939
3392
  export declare type CgiSetWhiteLedParam = {
2940
3393
  WhiteLed: CgiWhiteLed;
2941
3394
  };
@@ -3281,6 +3734,34 @@ export declare interface CompositeStreamPipOptions {
3281
3734
  rtspTransport?: 'tcp' | 'udp';
3282
3735
  }
3283
3736
 
3737
+ /**
3738
+ * Per-stream encoding entry inside `Compression`. Captured live on
3739
+ * E1-Zoom (TCP), Doorbell (UDP), Hub channel-0 (Argus 3E).
3740
+ *
3741
+ * Note: the camera-side field name is `frame`, NOT `frameRate`.
3742
+ * `videoEncType` is a numeric enum (`0` = h264, `1` = h265). The
3743
+ * `gop`/`encoderType`/`separateCfg` sub-blocks are firmware-dependent
3744
+ * (Hub-channel cameras carry them; standalone devices may not).
3745
+ */
3746
+ declare interface CompressionStream_2 {
3747
+ audio?: number | undefined;
3748
+ resolutionName?: string | undefined;
3749
+ width?: number | undefined;
3750
+ height?: number | undefined;
3751
+ frame?: number | undefined;
3752
+ bitRate?: number | undefined;
3753
+ encoderProfile?: string | undefined;
3754
+ videoEncType?: number | undefined;
3755
+ gop?: {
3756
+ cur?: number;
3757
+ max?: number;
3758
+ min?: number;
3759
+ } | undefined;
3760
+ encoderType?: string | undefined;
3761
+ [key: string]: unknown;
3762
+ }
3763
+ export { CompressionStream_2 as CompressionStream }
3764
+
3284
3765
  export declare function computeDeviceCapabilities(params: {
3285
3766
  channel: number;
3286
3767
  /** Device model name/type (best-effort). Used for heuristic capability detection. */
@@ -3415,6 +3896,8 @@ export declare function createNativeStream(api: ReolinkBaichuanApi, channel: num
3415
3896
  variant?: NativeVideoStreamVariant;
3416
3897
  /** Optional dedicated BaichuanClient for stream isolation. When omitted, uses api.client (shared). */
3417
3898
  client?: BaichuanClient;
3899
+ /** Cancellation signal — aborting wakes the idle sleep and exits the generator promptly. */
3900
+ signal?: AbortSignal;
3418
3901
  }): AsyncGenerator<{
3419
3902
  audio: boolean;
3420
3903
  data: Buffer;
@@ -3525,6 +4008,22 @@ export declare type DebugOptions = {
3525
4008
  };
3526
4009
  };
3527
4010
 
4011
+ /**
4012
+ * Decide whether a new sleep-inference poll should emit an event, given the
4013
+ * previously committed state and any pending hysteresis candidate.
4014
+ *
4015
+ * Rules:
4016
+ * 1. First observation (committed === undefined): always adopt as committed.
4017
+ * Emit "sleeping" but not "awake" — awake is the implicit default, so
4018
+ * emitting on startup would be noisy.
4019
+ * 2. Inferred matches committed: stable, clear any pending candidate.
4020
+ * 3. Inferred differs from committed but matches the pending candidate:
4021
+ * increment count. When count reaches hysteresisPolls, commit and emit.
4022
+ * 4. Inferred differs from committed AND from any pending candidate:
4023
+ * restart the candidate at count=1 (does not emit).
4024
+ */
4025
+ export declare function decideSleepInferenceTransition(input: SleepInferenceInput): SleepInferenceDecision;
4026
+
3528
4027
  /**
3529
4028
  * Determine if H.265 should be transcoded to H.264 based on client capabilities.
3530
4029
  *
@@ -3939,6 +4438,27 @@ export declare interface EmailTaskConfig {
3939
4438
  };
3940
4439
  }
3941
4440
 
4441
+ /**
4442
+ * Encoding configuration (getEnc response).
4443
+ * cmdId=56 (GetEnc) — payload is wrapped in `Compression`, not `Enc`.
4444
+ */
4445
+ export declare interface EncConfig {
4446
+ body?: {
4447
+ Compression?: {
4448
+ channelId?: number | undefined;
4449
+ isNoTranslateFrame?: number | undefined;
4450
+ mainStream?: CompressionStream_2 | undefined;
4451
+ subStream?: CompressionStream_2 | undefined;
4452
+ thirdStream?: CompressionStream_2 | undefined;
4453
+ separateCfg?: {
4454
+ encodeCfg?: number;
4455
+ [key: string]: unknown;
4456
+ } | undefined;
4457
+ [key: string]: unknown;
4458
+ };
4459
+ };
4460
+ }
4461
+
3942
4462
  export declare function encodeHeader(h: Omit<BaichuanHeader, "magic"> & {
3943
4463
  magic?: AnyBuffer;
3944
4464
  }): AnyBuffer;
@@ -3955,6 +4475,12 @@ export declare type EncryptionProtocol = {
3955
4475
  key: Buffer;
3956
4476
  };
3957
4477
 
4478
+ /**
4479
+ * Prepend the XML declaration if the body doesn't already start with
4480
+ * one. Reolink rejects payloads without it on most setX commands.
4481
+ */
4482
+ export declare function ensureXmlHeader(xml: string): string;
4483
+
3958
4484
  export declare interface Events {
3959
4485
  channel?: number;
3960
4486
  ai?: AIState;
@@ -4217,6 +4743,7 @@ export declare class Go2rtcTcpServer extends EventEmitter<{
4217
4743
  private totalFramesReceived;
4218
4744
  private totalVideoFramesWritten;
4219
4745
  private prebuffer;
4746
+ private audioInfo;
4220
4747
  constructor(options: Go2rtcTcpServerOptions);
4221
4748
  /** Start listening. Resolves once the TCP server is bound. */
4222
4749
  start(): Promise<void>;
@@ -4228,18 +4755,45 @@ export declare class Go2rtcTcpServer extends EventEmitter<{
4228
4755
  get go2rtcSourceUrl(): string | undefined;
4229
4756
  /** Number of currently connected clients. */
4230
4757
  get clientCount(): number;
4758
+ /**
4759
+ * Subscribe to the raw native stream for diagnostic purposes.
4760
+ * The subscriber receives the same frames the MPEG-TS muxer consumes
4761
+ * (pre-muxing). Counts as a "consumer" so the native stream is kept alive
4762
+ * for the lifetime of the subscription. If the stream is not already
4763
+ * running (battery camera, prestart=false), this starts it.
4764
+ */
4765
+ subscribeDiagnostic(id: string): Promise<AsyncGenerator<NativeFrame, void, unknown>>;
4766
+ /** Unsubscribe a diagnostic session and release its consumer slot. */
4767
+ unsubscribeDiagnostic(id: string): void;
4768
+ /**
4769
+ * Returns ADTS AAC audio metadata detected from the native stream, or
4770
+ * null if no audio frame has been observed yet (e.g. video-only cameras
4771
+ * or before the first audio packet arrives).
4772
+ */
4773
+ getAudioInfo(): {
4774
+ codec: "aac-adts";
4775
+ sampleRate: number;
4776
+ channels: number;
4777
+ configHex: string;
4778
+ } | null;
4231
4779
  private handleClient;
4232
4780
  private feedClient;
4233
4781
  /**
4234
- * Convert a native frame to wire-ready Annex-B.
4235
- * Audio frames are skipped raw TCP carries only video (Annex-B).
4236
- * go2rtc auto-detects the codec from SPS/PPS/VPS NALUs.
4782
+ * Convert a native video frame to Annex-B.
4783
+ * Returns null for audio frames (handled separately by muxAudio).
4237
4784
  */
4238
- private convertFrame;
4785
+ private convertVideoFrame;
4239
4786
  /** Check if an Annex-B buffer contains a keyframe (IDR for H.264, IRAP for H.265). */
4240
4787
  private isAnnexBKeyframe;
4241
4788
  /** Split Annex-B byte stream into individual NAL units. */
4242
4789
  private static splitAnnexBNals;
4790
+ /** True if `b` starts with an ADTS AAC syncword (0xFFF). */
4791
+ private static isAdtsAacFrame;
4792
+ /**
4793
+ * Parse an ADTS header into {sampleRate, channels, AudioSpecificConfig hex}.
4794
+ * Returns null when the buffer is not a valid ADTS frame.
4795
+ */
4796
+ private static parseAdtsSamplingInfo;
4243
4797
  private startNativeStream;
4244
4798
  private stopNativeStream;
4245
4799
  private startStreamHealthMonitor;
@@ -4554,6 +5108,27 @@ export declare interface IntercomOptions {
4554
5108
  api: ReolinkBaichuanApi;
4555
5109
  }
4556
5110
 
5111
+ /**
5112
+ * IR / supplemental light state (`getIrLights`). Captured live on every
5113
+ * test camera — `state` is the operator-facing toggle, `lightState` is
5114
+ * the camera's own runtime status. `doorbellLightState` /
5115
+ * `doorbellAbility` only appear on doorbell models.
5116
+ */
5117
+ export declare interface IrLightsConfig {
5118
+ body?: {
5119
+ LedState?: {
5120
+ channelId?: number | undefined;
5121
+ ledVersion?: number | undefined;
5122
+ IRLedBrightness?: number | undefined;
5123
+ state?: string | undefined;
5124
+ lightState?: string | undefined;
5125
+ doorbellLightState?: string | undefined;
5126
+ doorbellAbility?: number | undefined;
5127
+ [key: string]: unknown;
5128
+ };
5129
+ };
5130
+ }
5131
+
4557
5132
  export declare const isDualLenseModel: (model: string) => boolean;
4558
5133
 
4559
5134
  export declare function isH264KeyframeAnnexB(annexB: Buffer): boolean;
@@ -4578,6 +5153,87 @@ export declare function isH265KeyframeAnnexB(annexB: Buffer): boolean;
4578
5153
  */
4579
5154
  export declare const isNvrHubModel: (model?: string) => boolean;
4580
5155
 
5156
+ /**
5157
+ * ISP / image input configuration. Both `getIsp` (cmdId=25) and
5158
+ * `getImage` (cmdId=26) return identical payloads on observed firmwares
5159
+ * — the underlying VideoInput + InputAdvanceCfg blocks. Different
5160
+ * cmdIds preserved for backwards compatibility.
5161
+ */
5162
+ export declare interface IspConfig {
5163
+ body?: {
5164
+ VideoInput?: {
5165
+ channelId?: number | undefined;
5166
+ bright?: number | undefined;
5167
+ contrast?: number | undefined;
5168
+ saturation?: number | undefined;
5169
+ hue?: number | undefined;
5170
+ sharpen?: number | undefined;
5171
+ corridorAbility?: number | undefined;
5172
+ corridorMode?: string | undefined;
5173
+ [key: string]: unknown;
5174
+ };
5175
+ InputAdvanceCfg?: {
5176
+ channelId?: number | undefined;
5177
+ digitalChannel?: number | undefined;
5178
+ separateCfg?: {
5179
+ encType?: number;
5180
+ constantFrameRate?: number;
5181
+ [key: string]: unknown;
5182
+ } | undefined;
5183
+ PowerLineFrequency?: {
5184
+ mode?: string;
5185
+ enable?: number;
5186
+ [key: string]: unknown;
5187
+ } | undefined;
5188
+ Exposure?: {
5189
+ mode?: string;
5190
+ Gainctl?: {
5191
+ defMin?: number;
5192
+ defMax?: number;
5193
+ curMin?: number;
5194
+ curMax?: number;
5195
+ };
5196
+ Shutterctl?: {
5197
+ defMin?: number;
5198
+ defMax?: number;
5199
+ curMin?: number;
5200
+ curMax?: number;
5201
+ };
5202
+ shutterLevel?: string;
5203
+ gainLevel?: number;
5204
+ [key: string]: unknown;
5205
+ } | undefined;
5206
+ Scene?: {
5207
+ mode?: string;
5208
+ modeList?: string;
5209
+ Redgain?: {
5210
+ min?: number;
5211
+ max?: number;
5212
+ cur?: number;
5213
+ };
5214
+ Bluegain?: {
5215
+ min?: number;
5216
+ max?: number;
5217
+ cur?: number;
5218
+ };
5219
+ [key: string]: unknown;
5220
+ } | undefined;
5221
+ DayNight?: {
5222
+ mode?: string;
5223
+ IrcutMode?: string;
5224
+ Threshold?: string;
5225
+ [key: string]: unknown;
5226
+ } | undefined;
5227
+ BLC?: {
5228
+ enable?: number;
5229
+ mode?: string;
5230
+ [key: string]: unknown;
5231
+ } | undefined;
5232
+ [key: string]: unknown;
5233
+ };
5234
+ };
5235
+ }
5236
+
4581
5237
  /**
4582
5238
  * Check if a TCP error should trigger UDP fallback.
4583
5239
  * Only transport/connection errors should fallback, not authentication errors.
@@ -4631,6 +5287,33 @@ export declare type LoginResponseValue = {
4631
5287
 
4632
5288
  export declare type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
4633
5289
 
5290
+ /**
5291
+ * Privacy mask configuration (`getMask`). The `Shelter` block always
5292
+ * contains `enable` + `maxNum` + `shelterList`; tracked-shelter sub-
5293
+ * blocks (`trackEnable`, `trackShelterList`) are PTZ-only and
5294
+ * conditional on the camera supporting motion-tracking. Hub-channel
5295
+ * cameras include `separateCfg` + `logicChannel`.
5296
+ */
5297
+ export declare interface MaskConfig {
5298
+ body?: {
5299
+ Shelter?: {
5300
+ channelId?: number | undefined;
5301
+ enable?: number | undefined;
5302
+ maxNum?: number | undefined;
5303
+ shelterList?: unknown;
5304
+ trackEnable?: number | undefined;
5305
+ maxTrackShelterNum?: number | undefined;
5306
+ trackShelterList?: unknown;
5307
+ separateCfg?: {
5308
+ shelter?: number;
5309
+ [key: string]: unknown;
5310
+ } | undefined;
5311
+ logicChannel?: number | undefined;
5312
+ [key: string]: unknown;
5313
+ };
5314
+ };
5315
+ }
5316
+
4634
5317
  /**
4635
5318
  * Mask UID for logging (show first 4 and last 4 characters).
4636
5319
  */
@@ -4780,8 +5463,99 @@ export declare interface MotionEvent {
4780
5463
  source?: "md" | "pir" | "unknown";
4781
5464
  }
4782
5465
 
5466
+ /**
5467
+ * Stateful MPEG-TS muxer. Each instance has its own continuity counters —
5468
+ * create one per output stream (or per client connection for prebuffer replay).
5469
+ */
5470
+ export declare class MpegTsMuxer {
5471
+ private readonly videoStreamType;
5472
+ private readonly includeAudio;
5473
+ private patCc;
5474
+ private pmtCc;
5475
+ private videoCc;
5476
+ private audioCc;
5477
+ private framesSinceTableSend;
5478
+ private tablesSent;
5479
+ constructor(options: MpegTsMuxerOptions);
5480
+ /**
5481
+ * Mux a video frame (Annex-B H.264 or H.265) into MPEG-TS packets.
5482
+ * PAT and PMT are emitted before keyframes and periodically.
5483
+ *
5484
+ * @param annexBData - Annex-B video data (with start codes)
5485
+ * @param ptsUs - Presentation timestamp in microseconds
5486
+ * @param isKeyframe - Whether this is an IDR / IRAP frame
5487
+ */
5488
+ muxVideo(annexBData: Buffer, ptsUs: number, isKeyframe: boolean): Buffer;
5489
+ /**
5490
+ * Mux an audio frame (ADTS AAC) into MPEG-TS packets.
5491
+ * Returns an empty Buffer when includeAudio is false.
5492
+ *
5493
+ * @param adtsData - Raw ADTS AAC frame (starting with 0xFF 0xF1/0xF9 syncword)
5494
+ * @param ptsUs - Presentation timestamp in microseconds
5495
+ */
5496
+ muxAudio(adtsData: Buffer, ptsUs: number): Buffer;
5497
+ /** Reset all continuity counters and table state (e.g. after stream restart). */
5498
+ reset(): void;
5499
+ }
5500
+
5501
+ /**
5502
+ * MPEG-TS Muxer for H.264/H.265 video + ADTS AAC audio.
5503
+ *
5504
+ * Produces 188-byte MPEG-TS packets suitable for feeding to go2rtc via a
5505
+ * plain TCP connection (`tcp://127.0.0.1:{port}`). go2rtc auto-detects the
5506
+ * container format from the 0x47 sync byte and extracts both video and audio.
5507
+ *
5508
+ * Stream layout:
5509
+ * PID 0x0000 — PAT (Program Association Table)
5510
+ * PID 0x1000 — PMT (Program Map Table)
5511
+ * PID 0x0100 — Video elementary stream (H.264 or H.265, Annex-B)
5512
+ * PID 0x0101 — Audio elementary stream (AAC-ADTS, stream type 0x0F)
5513
+ *
5514
+ * Each `MpegTsMuxer` instance is independent: continuity counters are
5515
+ * per-instance so multiple concurrent streams do not corrupt each other.
5516
+ *
5517
+ * Usage:
5518
+ * const muxer = new MpegTsMuxer({ videoType: "H265", includeAudio: true });
5519
+ * const tsBytes = muxer.muxVideo(annexBBuffer, ptsUs, isKeyframe);
5520
+ * const tsBytes = muxer.muxAudio(adtsBuffer, ptsUs);
5521
+ */
5522
+ export declare interface MpegTsMuxerOptions {
5523
+ /** Video codec type. */
5524
+ videoType: "H264" | "H265";
5525
+ /**
5526
+ * Whether to include an audio PID (0x0101) in the PMT.
5527
+ * When true, audio frames muxed via muxAudio() are wrapped in PES packets
5528
+ * on PID 0x0101 (AAC-ADTS, stream type 0x0F).
5529
+ * Default: true.
5530
+ */
5531
+ includeAudio?: boolean;
5532
+ }
5533
+
5534
+ declare type NativeFrame = {
5535
+ audio: boolean;
5536
+ data: Buffer;
5537
+ codec: string | null;
5538
+ sampleRate: number | null;
5539
+ microseconds: number | null;
5540
+ videoType?: "H264" | "H265";
5541
+ isKeyframe?: boolean;
5542
+ };
5543
+
4783
5544
  export declare type NativeVideoStreamVariant = "default" | "autotrack" | "telephoto";
4784
5545
 
5546
+ /**
5547
+ * Normalize human-friendly day/night labels to the camera's expected
5548
+ * lowercase form. Mirrors reolink_aio's `SetIsp` post-processing
5549
+ * (`& → And`, capitalize first letter).
5550
+ */
5551
+ export declare function normalizeDayNightMode(input: string): string;
5552
+
5553
+ /**
5554
+ * Normalize "On"/"Off" / "open"/"close" / boolean-ish inputs to the
5555
+ * `open`/`close` enum the camera expects on LED-control commands.
5556
+ */
5557
+ export declare function normalizeOpenClose(input: string): string;
5558
+
4785
5559
  /**
4786
5560
  * Normalize UID string (trim and return undefined if empty).
4787
5561
  */
@@ -4926,6 +5700,13 @@ export declare function parseRecordingFileName(fileName: string): ParsedRecordin
4926
5700
 
4927
5701
  export declare function parseSupportXml(xml: string): SupportInfo | undefined;
4928
5702
 
5703
+ /**
5704
+ * Patch a child tag inside a named parent block. Used for nested
5705
+ * structures like `<DayNight><mode>...</mode></DayNight>` where the
5706
+ * same `<mode>` tag appears under multiple parents.
5707
+ */
5708
+ export declare function patchNestedTag(xml: string, parent: string, child: string, value: string | number | boolean | undefined): string;
5709
+
4929
5710
  export declare type PipPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center" | "top-center" | "bottom-center" | "left-center" | "right-center";
4930
5711
 
4931
5712
  /**
@@ -4948,6 +5729,17 @@ export declare interface PirState {
4948
5729
  state?: {
4949
5730
  enable?: number;
4950
5731
  channel?: number;
5732
+ /** PIR sensitivity (typically 1..100). Camera-side field is
5733
+ * `sensiValue` in the cmd_id 212 response. */
5734
+ sensitive?: number;
5735
+ /** False-positive reduction toggle (`reduceFalseAlarm` on the
5736
+ * wire). 0/1. */
5737
+ reduceAlarm?: number;
5738
+ /** Cooldown between consecutive PIR triggers (seconds). */
5739
+ interval?: number;
5740
+ /** Firmware-advertised max value for `interval`. Drives the
5741
+ * upper bound of operator-facing sliders. */
5742
+ intervalMax?: number;
4951
5743
  [key: string]: unknown;
4952
5744
  };
4953
5745
  }
@@ -5218,7 +6010,17 @@ export declare class ReolinkBaichuanApi {
5218
6010
  private statePollingInterval;
5219
6011
  private udpSleepInferenceInterval;
5220
6012
  private readonly udpLastInferredSleepStateByChannel;
6013
+ /**
6014
+ * Per-channel pending sleep-state candidate for hysteresis.
6015
+ * When the inference flips to a new state we require N consecutive polls
6016
+ * of that same state before committing it — this filters out transient
6017
+ * flapping caused by non-waking traffic drifting in/out of the 10 s
6018
+ * getSleepStatus() observation window during stream teardown.
6019
+ */
6020
+ private readonly udpPendingSleepStateByChannel;
5221
6021
  private readonly udpSleepInferenceIntervalMs;
6022
+ /** Consecutive inference polls required to commit a new sleeping/awake state. */
6023
+ private readonly udpSleepInferenceHysteresisPolls;
5222
6024
  private lastMotionState;
5223
6025
  private lastAiState;
5224
6026
  private aiStatePollingDisabled;
@@ -7007,6 +7809,185 @@ export declare class ReolinkBaichuanApi {
7007
7809
  * Fetches events/motion/AI state for all channels via CGI and merges results per channel.
7008
7810
  */
7009
7811
  getAllChannelsEvents(options?: Parameters<ReolinkCgiApi["getAllChannelsEvents"]>[0]): ReturnType<ReolinkCgiApi["getAllChannelsEvents"]>;
7812
+ /**
7813
+ * GetEnc via Baichuan (cmdId=56). Returns the `<Compression>` block:
7814
+ * per-stream `mainStream` / `subStream` / `thirdStream` with `audio`
7815
+ * flag, `width`, `height`, `frame` (NOT `frameRate`), `bitRate`,
7816
+ * `videoEncType` (0=h264, 1=h265), `encoderProfile`, `gop`. Mirrors
7817
+ * reolink_aio's `GetEnc` — note the wire payload wraps everything
7818
+ * in `Compression`, not `Enc`.
7819
+ */
7820
+ getEnc(channel?: number, options?: {
7821
+ timeoutMs?: number;
7822
+ }): Promise<EncConfig>;
7823
+ /**
7824
+ * SetEnc via Baichuan (cmdId=57). Read-modify-write — preserves
7825
+ * unspecified fields. Mirrors reolink_aio's `SetEnc`.
7826
+ *
7827
+ * @param channel - Channel number (0-based)
7828
+ * @param patch - Fields to update on `mainStream` and/or `subStream`,
7829
+ * plus a top-level `audio` toggle (0/1). Pass only what you want
7830
+ * to change.
7831
+ */
7832
+ setEnc(channel: number, patch: {
7833
+ audio?: 0 | 1;
7834
+ mainStream?: {
7835
+ bitRate?: number;
7836
+ frameRate?: number;
7837
+ videoEncType?: "h264" | "h265";
7838
+ };
7839
+ subStream?: {
7840
+ bitRate?: number;
7841
+ frameRate?: number;
7842
+ videoEncType?: "h264" | "h265";
7843
+ };
7844
+ }, options?: {
7845
+ timeoutMs?: number;
7846
+ }): Promise<void>;
7847
+ /**
7848
+ * SetImage via Baichuan (cmdId=25, read via cmdId=26). Patches the
7849
+ * `<VideoInput>` block: bright / contrast / saturation / hue /
7850
+ * sharpen. Mirrors reolink_aio's `SetImage`.
7851
+ */
7852
+ setImage(channel: number, patch: {
7853
+ bright?: number;
7854
+ contrast?: number;
7855
+ saturation?: number;
7856
+ hue?: number;
7857
+ sharpen?: number;
7858
+ }, options?: {
7859
+ timeoutMs?: number;
7860
+ }): Promise<void>;
7861
+ /**
7862
+ * SetIsp via Baichuan (cmdId=25 for image side, cmdId=297 for
7863
+ * dayNightThreshold). Patches the `<InputAdvanceCfg>` block:
7864
+ * `DayNight/mode`, `Exposure/mode`, `binning_mode`, `hdrSwitch`.
7865
+ * Mirrors reolink_aio's `SetIsp`.
7866
+ *
7867
+ * @param channel - Channel number (0-based)
7868
+ * @param patch - Fields to update. `dayNight` accepts the camera's
7869
+ * raw enum (`color`, `auto`, `blackAndWhite`, …) — pass it as the
7870
+ * camera reports it (PascalCase / dotted forms get normalized
7871
+ * server-side).
7872
+ */
7873
+ setIsp(channel: number, patch: {
7874
+ dayNight?: string;
7875
+ exposure?: string;
7876
+ binningMode?: number;
7877
+ hdr?: 0 | 1;
7878
+ dayNightThreshold?: number;
7879
+ }, options?: {
7880
+ timeoutMs?: number;
7881
+ }): Promise<void>;
7882
+ /**
7883
+ * GetIsp via Baichuan (cmdId=26). Convenience alias of
7884
+ * `getVideoInput()` so callers that switched from CGI keep the
7885
+ * familiar name. Both return the merged VideoInput +
7886
+ * InputAdvanceCfg blob.
7887
+ */
7888
+ getIsp(channel?: number, options?: {
7889
+ timeoutMs?: number;
7890
+ }): Promise<IspConfig>;
7891
+ /** GetImage via Baichuan (cmdId=26). Same payload as `getIsp` —
7892
+ * Reolink merged VideoInput + InputAdvanceCfg under one cmdId. */
7893
+ getImage(channel?: number, options?: {
7894
+ timeoutMs?: number;
7895
+ }): Promise<IspConfig>;
7896
+ /**
7897
+ * GetIrLights via Baichuan (cmdId=208). Returns LedState block:
7898
+ * `IRLedBrightness`, `state` (ir on/off), `lightState` (status LED
7899
+ * open/close), `doorbellLightState`. Mirrors reolink_aio's
7900
+ * `get_status_led`.
7901
+ */
7902
+ getIrLights(channel?: number, options?: {
7903
+ timeoutMs?: number;
7904
+ }): Promise<IrLightsConfig>;
7905
+ /**
7906
+ * SetIrLights via Baichuan (cmdId=209, read via cmdId=208). Patches
7907
+ * IR LED + status LED + doorbell LED + IR brightness. Mirrors
7908
+ * reolink_aio's `set_status_led`.
7909
+ *
7910
+ * @param channel - Channel number (0-based)
7911
+ * @param patch - `irState` ("On" | "Off" | "Auto"), `lightState`
7912
+ * (status LED), `doorbellLightState`, `irBrightness` (0..255).
7913
+ * Camera-side accepts lowercase strings (`open`/`close`); the
7914
+ * helper normalizes from the friendly variants.
7915
+ */
7916
+ setIrLights(channel: number, patch: {
7917
+ irState?: "On" | "Off" | "Auto" | string;
7918
+ lightState?: "On" | "Off" | string;
7919
+ doorbellLightState?: "On" | "Off" | string;
7920
+ irBrightness?: number;
7921
+ }, options?: {
7922
+ timeoutMs?: number;
7923
+ }): Promise<void>;
7924
+ /**
7925
+ * SetAudioCfg via Baichuan (cmdId=265, read via cmdId=264). Patches
7926
+ * volume / talk-and-reply / visitor settings. Mirrors reolink_aio's
7927
+ * `SetAudioCfg`.
7928
+ */
7929
+ setAudioCfg(channel: number, patch: {
7930
+ volume?: number;
7931
+ talkAndReplyVolume?: number;
7932
+ visitorVolume?: number;
7933
+ visitorLoudspeaker?: number;
7934
+ }, options?: {
7935
+ timeoutMs?: number;
7936
+ }): Promise<void>;
7937
+ /**
7938
+ * GetMask (privacy mask) via Baichuan (cmdId=52). Returns the
7939
+ * `<Shelter>` block — `enable` flag + `shelterList`. Mirrors
7940
+ * reolink_aio's `GetMask`.
7941
+ */
7942
+ getMask(channel?: number, options?: {
7943
+ timeoutMs?: number;
7944
+ }): Promise<MaskConfig>;
7945
+ /**
7946
+ * SetMask (privacy mask) via Baichuan (cmdId=53, read via cmdId=52).
7947
+ * Toggles the `<Shelter><enable>` flag. Mirrors reolink_aio's
7948
+ * `SetMask` (which only touches enable too — shelter zone editing
7949
+ * goes through a separate flow).
7950
+ */
7951
+ setMask(channel: number, patch: {
7952
+ enable?: 0 | 1 | boolean;
7953
+ }, options?: {
7954
+ timeoutMs?: number;
7955
+ }): Promise<void>;
7956
+ /**
7957
+ * GetAudioNoise via Baichuan (cmdId=439). Reads `enable` + `level`
7958
+ * from the aiDenoise block. Mirrors reolink_aio's `GetAudioNoise`.
7959
+ *
7960
+ * Note: `getAiDenoise` already returns the same payload typed as
7961
+ * `AiDenoiseConfig`. This getter exists for naming parity with
7962
+ * reolink_aio + the reolink CGI.
7963
+ */
7964
+ getAudioNoise(channel?: number, options?: {
7965
+ timeoutMs?: number;
7966
+ }): Promise<AudioNoiseConfig>;
7967
+ /**
7968
+ * SetAudioNoise via Baichuan (cmdId=440, read via cmdId=439).
7969
+ * Mirrors reolink_aio's `SetAudioNoise` — `level <= 0` flips the
7970
+ * enable flag off; positive values turn it on and update the level.
7971
+ */
7972
+ setAudioNoise(channel: number, level: number, options?: {
7973
+ timeoutMs?: number;
7974
+ }): Promise<void>;
7975
+ /**
7976
+ * GetAutoFocus via Baichuan (cmdId=224). Returns the `<AutoFocus>`
7977
+ * block — only `disable` (0 = AF on, 1 = AF off). Mirrors
7978
+ * reolink_aio's `GetAutoFocus`.
7979
+ */
7980
+ getAutoFocus(channel: number, options?: {
7981
+ timeoutMs?: number;
7982
+ }): Promise<AutoFocusConfig>;
7983
+ /**
7984
+ * SetAutoFocus via Baichuan (cmdId=225). Mirrors reolink_aio's
7985
+ * `SetAutoFocus`. Note: write-only command — the payload is built
7986
+ * from scratch (no read-modify-write needed).
7987
+ */
7988
+ setAutoFocus(channel: number, disable: 0 | 1 | boolean, options?: {
7989
+ timeoutMs?: number;
7990
+ }): Promise<void>;
7010
7991
  /**
7011
7992
  * Passthrough to ReolinkCgiApi.getAllChannelsBatteryInfo.
7012
7993
  * Fetches battery info for all channels via CGI (merged with channel status sleep flag).
@@ -8073,6 +9054,45 @@ export declare class ReolinkCgiApi {
8073
9054
  GetPirInfo(channel?: number): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
8074
9055
  SetPirInfo(pirInfo: CgiSetPirInfoParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
8075
9056
  GetPtzPreset(channel?: number): Promise<ReolinkCmdResponse[]>;
9057
+ GetIsp(channel?: number): Promise<Array<ReolinkCmdResponseExt<CgiGetIspValue>>>;
9058
+ SetIsp(isp: CgiSetIspParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9059
+ GetImage(channel?: number): Promise<Array<ReolinkCmdResponseExt<CgiGetImageValue>>>;
9060
+ SetImage(image: CgiSetImageParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9061
+ GetAudioCfg(channel?: number): Promise<Array<ReolinkCmdResponseExt<CgiGetAudioCfgValue>>>;
9062
+ SetAudioCfg(audio: CgiSetAudioCfgParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9063
+ SetEnc(enc: CgiSetEncParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9064
+ GetMdAlarm(channel?: number): Promise<Array<ReolinkCmdResponseExt<CgiGetMdAlarmValue>>>;
9065
+ SetMdAlarm(md: CgiSetMdAlarmParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9066
+ GetIrLights(channel?: number): Promise<Array<ReolinkCmdResponseExt<CgiGetIrLightsValue>>>;
9067
+ SetIrLights(ir: CgiSetIrLightsParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9068
+ GetAiCfg(channel?: number): Promise<Array<ReolinkCmdResponseExt<CgiGetAiCfgValue>>>;
9069
+ SetAiCfg(ai: CgiSetAiCfgParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9070
+ GetMask(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetMaskValue>>>;
9071
+ SetMask(mask: CgiSetMaskParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9072
+ GetAudioNoise(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetAudioNoiseValue>>>;
9073
+ SetAudioNoise(noise: CgiSetAudioNoiseParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9074
+ GetRec(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetRecValue>>>;
9075
+ SetRec(rec: CgiSetRecParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9076
+ /** Newer firmwares advertise `GetRecV20` / `SetRecV20` with the
9077
+ * weekly-schedule `table` field. Same payload shape as `Rec`. */
9078
+ GetRecV20(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetRecValue>>>;
9079
+ SetRecV20(rec: CgiSetRecParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9080
+ GetEmail(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetEmailValue>>>;
9081
+ SetEmail(email: CgiSetEmailParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9082
+ /** V20 variant on newer firmwares with weekly-schedule `table`. */
9083
+ GetEmailV20(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetEmailValue>>>;
9084
+ SetEmailV20(email: CgiSetEmailParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9085
+ GetPush(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetPushValue>>>;
9086
+ SetPush(push: CgiSetPushParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9087
+ GetPushV20(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetPushValue>>>;
9088
+ SetPushV20(push: CgiSetPushParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9089
+ GetAudioAlarm(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetAudioAlarmValue>>>;
9090
+ SetAudioAlarm(audio: CgiSetAudioAlarmParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9091
+ SetAudioAlarmV20(audio: CgiSetAudioAlarmParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9092
+ GetAutoFocus(channel: number): Promise<Array<ReolinkCmdResponseExt<CgiGetAutoFocusValue>>>;
9093
+ SetAutoFocus(af: CgiSetAutoFocusParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
9094
+ GetAiAlarm(channel: number, aiType: string): Promise<Array<ReolinkCmdResponseExt<CgiGetAiAlarmValue>>>;
9095
+ SetAiAlarm(ai: CgiSetAiAlarmParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
8076
9096
  GetAudioAlarmV20(channel?: number): Promise<ReolinkCmdResponse[]>;
8077
9097
  AudioAlarmPlay(params: CgiAudioAlarmPlayParam): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
8078
9098
  GetNetPort(): Promise<Array<ReolinkCmdResponseExt<JsonValue>>>;
@@ -8941,6 +9961,31 @@ export declare interface SirenStatusConfig {
8941
9961
  };
8942
9962
  }
8943
9963
 
9964
+ export declare interface SleepInferenceDecision {
9965
+ /** The event to dispatch, or null if no event should fire this poll. */
9966
+ emit: "sleeping" | "awake" | null;
9967
+ /** New committed state to store (never "unknown"). */
9968
+ nextCommitted: SleepState;
9969
+ /** New pending candidate to store, or undefined to clear it. */
9970
+ nextPending: SleepInferencePending | undefined;
9971
+ }
9972
+
9973
+ export declare interface SleepInferenceInput {
9974
+ /** State returned by the current getSleepStatus() poll — must not be "unknown". */
9975
+ inferred: Exclude<SleepState, "unknown">;
9976
+ /** Previously committed state (undefined = first observation after inference start). */
9977
+ committed: SleepState | undefined;
9978
+ /** Pending candidate state and consecutive match count, if any. */
9979
+ pending: SleepInferencePending | undefined;
9980
+ /** Consecutive polls of the same inferred state required to commit. */
9981
+ hysteresisPolls: number;
9982
+ }
9983
+
9984
+ export declare interface SleepInferencePending {
9985
+ state: SleepState;
9986
+ count: number;
9987
+ }
9988
+
8944
9989
  export declare type SleepState = "awake" | "sleeping" | "unknown";
8945
9990
 
8946
9991
  /**