@mega-yfue/eufy-sdk 0.5.0-beta.12 → 0.5.0-beta.14

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.
@@ -551,16 +551,25 @@ export type AudioCodec = "aac-lc" | "aac-eld" | "g711a";
551
551
  /**
552
552
  * One audio access unit, carrying the codec the station declared for it.
553
553
  *
554
- * Sample rate and channel count are deliberately absent: they are not on the wire. The v6 app assumes
555
- * 16 kHz mono for every audio type rather than reading them, so the SDK does not invent fields the
556
- * device never sent.
554
+ * Sample rate and channel count are absent for `aac-lc` and `g711a`: they are not on the wire, and the v6 app
555
+ * assumes 16 kHz mono for every audio type rather than reading them. An `aac-lc` frame is one ADTS frame and
556
+ * `g711a` is raw A-law. An `aac-eld` frame is one raw access unit with no transport framing, so it carries the
557
+ * AudioSpecificConfig that decodes it.
557
558
  */
558
- export interface LiveAudioFrame {
559
+ export type LiveAudioFrame = {
559
560
  /** Codec declared in the frame header. */
560
- codec: AudioCodec;
561
- /** Elementary-stream bytes (ADTS-framed for the two AAC profiles). */
561
+ codec: "aac-lc" | "g711a";
562
+ /** One ADTS frame for `aac-lc`, raw A-law samples for `g711a`. */
562
563
  data: Buffer;
563
- }
564
+ config?: undefined;
565
+ } | {
566
+ /** Codec declared in the frame header. */
567
+ codec: "aac-eld";
568
+ /** One raw AAC-ELD access unit. */
569
+ data: Buffer;
570
+ /** AudioSpecificConfig (ISO/IEC 14496-3) that decodes `data`. */
571
+ config: Buffer;
572
+ };
564
573
  /**
565
574
  * One fragmented-MP4 (CMAF) output unit from the native muxer. `init` (the `ftyp`+`moov` init
566
575
  * segment) is present exactly once, on the first fragment; every fragment carries a `moof`+`mdat`
package/dist/index.js CHANGED
@@ -8336,8 +8336,6 @@ var MODE_CTRL_FIELD = {
8336
8336
  SEQ: 2
8337
8337
  };
8338
8338
  var ModeCtrlMethod = {
8339
- /** Live-verified on a T2351. Zero, so it is omitted from the wire per the proto3 default rule. */
8340
- START_AUTO_CLEAN: 0,
8341
8339
  /** Live-verified on a T2351. */
8342
8340
  START_GOHOME: 6,
8343
8341
  /** Live-verified on a T2351. */
@@ -8361,6 +8359,8 @@ var ModeCtrlMethod = {
8361
8359
  START_GLOBAL_CRUISE: 20
8362
8360
  };
8363
8361
  var ModeCtrlParamMethod = {
8362
+ /** `START_AUTO_CLEAN` with an `AutoClean` payload — clean the whole floor. */
8363
+ AUTO: { method: 0, param: 3 },
8364
8364
  /** `START_SELECT_ROOMS_CLEAN` — clean the named rooms of a named map. */
8365
8365
  SELECT_ROOMS: { method: 1, param: 4 },
8366
8366
  /** `START_SELECT_ZONES_CLEAN` — clean the given rectangles of a named map. */
@@ -8397,6 +8397,7 @@ var SELECT_ZONES_FIELD = {
8397
8397
  POINT_Y: 2
8398
8398
  };
8399
8399
  var SCENE_CLEAN_ID = 1;
8400
+ var AUTO_CLEAN_TIMES = 1;
8400
8401
  function encodeModeCtrlParam(method2, paramField, build) {
8401
8402
  return rawDp((w) => {
8402
8403
  if (method2 !== 0)
@@ -8443,14 +8444,17 @@ function encodeSceneClean(sceneId) {
8443
8444
  const { method: method2, param } = ModeCtrlParamMethod.SCENE;
8444
8445
  return encodeModeCtrlParam(method2, param, (p) => p.int(SCENE_CLEAN_ID, sceneId));
8445
8446
  }
8447
+ function encodeAutoClean() {
8448
+ const { method: method2, param } = ModeCtrlParamMethod.AUTO;
8449
+ return encodeModeCtrlParam(method2, param, (p) => p.int(AUTO_CLEAN_TIMES, 1));
8450
+ }
8446
8451
  var modeCtrlSeq = 111;
8447
8452
  function nextModeCtrlSeq() {
8448
8453
  return ++modeCtrlSeq;
8449
8454
  }
8450
8455
  function encodeModeCtrl(method2, seq) {
8451
8456
  return rawDp((w) => {
8452
- if (method2 !== 0)
8453
- w.int(MODE_CTRL_FIELD.METHOD, method2);
8457
+ w.int(MODE_CTRL_FIELD.METHOD, method2);
8454
8458
  w.int(MODE_CTRL_FIELD.SEQ, seq);
8455
8459
  });
8456
8460
  }
@@ -10292,8 +10296,8 @@ var VACUUM_CLEAN_MEMBERS = {
10292
10296
  provenance: "mega",
10293
10297
  description: "Stop smart-follow mode (ModeCtrlRequest method 18 over DP 152). Method number not captured \u2014 unverified."
10294
10298
  },
10295
- /** Start an auto-clean run via ModeCtrlRequest method 0 (DP 152). AIoT only — Tuya write unverified. */
10296
- startCleaning: method(({ sink }) => () => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeModeCtrl(ModeCtrlMethod.START_AUTO_CLEAN, nextModeCtrlSeq()))), "Start an auto-clean run (ModeCtrlRequest method 0 over DP 152).", isAiotVacuum),
10299
+ /** Start an auto-clean run via ModeCtrlRequest method 0 with one `AutoClean` pass (DP 152). AIoT only — Tuya write unverified. */
10300
+ startCleaning: method(({ sink }) => () => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeAutoClean())), "Start an auto-clean run (ModeCtrlRequest method 0, AutoClean clean_times 1, over DP 152).", isAiotVacuum),
10297
10301
  /** Return to the dock via ModeCtrlRequest method 6 (DP 152). AIoT only — Tuya write unverified. */
10298
10302
  returnToDock: method(({ sink }) => () => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeModeCtrl(ModeCtrlMethod.START_GOHOME, nextModeCtrlSeq()))), "Return to the dock (ModeCtrlRequest method 6 over DP 152).", isAiotVacuum),
10299
10303
  /** Pause the current cleaning task via ModeCtrlRequest method 13 (DP 152). AIoT only — Tuya write unverified. */
@@ -17927,6 +17931,7 @@ var AUDIO_HEADER_LEN = 16;
17927
17931
  var AUDIO_TYPE_OFFSET = 5;
17928
17932
  var SC4 = Buffer.from([0, 0, 0, 1]);
17929
17933
  var SC3 = Buffer.from([0, 0, 1]);
17934
+ var AAC_ELD_AUDIO_SPECIFIC_CONFIG = Buffer.from("f8f03000", "hex");
17930
17935
  var AUDIO_CODECS = { 0: "aac-lc", 2: "g711a", 7: "aac-eld" };
17931
17936
  var MAX_TRACED_DECODE_FAILURES = 3;
17932
17937
  var DEFAULT_KEEPALIVE_MS = 3e3;
@@ -18155,7 +18160,7 @@ var LiveStream = class extends EventEmitter3 {
18155
18160
  if (!codec) {
18156
18161
  this.logger.debug(`[live] dropping audio frame: unknown codec id ${codecId ?? "missing"}`);
18157
18162
  } else {
18158
- this.emit("audio", { codec, data: audio });
18163
+ this.emit("audio", codec === "aac-eld" ? { codec, data: audio, config: AAC_ELD_AUDIO_SPECIFIC_CONFIG } : { codec, data: audio });
18159
18164
  }
18160
18165
  }
18161
18166
  }
@@ -20173,7 +20178,7 @@ var CODEC_BOXES = {
20173
20178
  h264: { sample: "avc1", config: "avcC" },
20174
20179
  h265: { sample: "hvc1", config: "hvcC" }
20175
20180
  };
20176
- var AAC_ELD_SAMPLES_PER_FRAME = 512;
20181
+ var AAC_ELD_SAMPLES_PER_FRAME = 480;
20177
20182
  var ADTS_FREQUENCY_INDEX_16K = 8;
20178
20183
  var ADTS_CHANNELS_MONO = 1;
20179
20184
  var Fmp4Muxer = class {
@@ -20191,6 +20196,8 @@ var Fmp4Muxer = class {
20191
20196
  lastVideoTimestampMs;
20192
20197
  audioRequested;
20193
20198
  audioCodec;
20199
+ /** Decoder config of an AAC-ELD track, taken from its frames; absent for AAC-LC, whose `esds` config is fixed. */
20200
+ audioConfig;
20194
20201
  audioDisabled = false;
20195
20202
  audioSamples = [];
20196
20203
  audioBaseDecodeTime = 0;
@@ -20257,7 +20264,10 @@ var Fmp4Muxer = class {
20257
20264
  }
20258
20265
  return void 0;
20259
20266
  }
20260
- /** Add one station-declared AAC access unit to the audio track. G.711 remains available via `live()`. */
20267
+ /**
20268
+ * Add one station-declared AAC access unit to the audio track: an ADTS frame for AAC-LC, a raw access unit
20269
+ * described by its frame's config for AAC-ELD. G.711 remains available via `live()`.
20270
+ */
20261
20271
  pushAudio(frame, timestampMs = now()) {
20262
20272
  if (!this.audioRequested || this.audioDisabled)
20263
20273
  return void 0;
@@ -20273,12 +20283,19 @@ var Fmp4Muxer = class {
20273
20283
  if (this.audioCodec && this.audioCodec !== frame.codec) {
20274
20284
  return this.disableAudio();
20275
20285
  }
20276
- const header = parseAdtsHeader(frame.data);
20277
- if (!header || header.frameLength > frame.data.length) {
20278
- throw new Error(`fMP4 muxer: ${frame.codec} frame is not a complete ADTS access unit`);
20279
- }
20280
- if (header.frequencyIndex !== ADTS_FREQUENCY_INDEX_16K || header.channels !== ADTS_CHANNELS_MONO) {
20281
- return this.disableAudio();
20286
+ let sample;
20287
+ if (frame.codec === "aac-eld") {
20288
+ this.audioConfig = frame.config;
20289
+ sample = frame.data;
20290
+ } else {
20291
+ const header = parseAdtsHeader(frame.data);
20292
+ if (!header || header.frameLength > frame.data.length) {
20293
+ throw new Error(`fMP4 muxer: ${frame.codec} frame is not a complete ADTS access unit`);
20294
+ }
20295
+ if (header.frequencyIndex !== ADTS_FREQUENCY_INDEX_16K || header.channels !== ADTS_CHANNELS_MONO) {
20296
+ return this.disableAudio();
20297
+ }
20298
+ sample = frame.data.subarray(header.headerLength, header.frameLength);
20282
20299
  }
20283
20300
  this.audioCodec = frame.codec;
20284
20301
  this.firstAudioTimestampMs ??= timestampMs;
@@ -20290,7 +20307,7 @@ var Fmp4Muxer = class {
20290
20307
  this.audioSamples[this.audioSamples.length - 1].duration = measured;
20291
20308
  }
20292
20309
  this.audioSamples.push({
20293
- data: frame.data.subarray(header.headerLength, header.frameLength),
20310
+ data: sample,
20294
20311
  duration: frame.codec === "aac-eld" ? AAC_ELD_SAMPLES_PER_FRAME : AAC_SAMPLES_PER_FRAME,
20295
20312
  keyframe: true
20296
20313
  });
@@ -20563,7 +20580,7 @@ var Fmp4Muxer = class {
20563
20580
  return box("mp4a", head, this.esds());
20564
20581
  }
20565
20582
  esds() {
20566
- const config = this.audioCodec === "aac-eld" ? Buffer.from([248, 240, 32]) : Buffer.from([20, 8]);
20583
+ const config = this.audioConfig ?? Buffer.from([20, 8]);
20567
20584
  const specific = descriptor(5, config);
20568
20585
  const decoder = descriptor(4, Buffer.concat([Buffer.from([64, 21, 0, 0, 0]), u32(64e3), u32(32e3), specific]));
20569
20586
  const sl = descriptor(6, Buffer.from([2]));