@mega-yfue/eufy-sdk 0.5.0-beta.6 → 0.5.0-beta.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/index.js CHANGED
@@ -16810,11 +16810,13 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
16810
16810
  if (advance > SEQUENCE_LOOKBACK) {
16811
16811
  if (65536 - advance <= STALE_RETRANSMIT_DEPTH)
16812
16812
  return;
16813
- if (this.pendingByDataType.has(dataType) && this.tracedDatagramGaps++ < MAX_TRACED_DATAGRAM_GAPS)
16813
+ if ((dataType === P2PDataType.VIDEO || this.pendingByDataType.has(dataType)) && this.tracedDatagramGaps++ < MAX_TRACED_DATAGRAM_GAPS)
16814
16814
  this.trace({ phase: "sequence-restart", dataType });
16815
16815
  this.clearReorderTimer(dataType);
16816
16816
  this.reorderByType.delete(dataType);
16817
16817
  this.pendingByDataType.delete(dataType);
16818
+ if (dataType === P2PDataType.VIDEO)
16819
+ this.emit("videoGap");
16818
16820
  this.lastSeqByType.set(dataType, seqNo);
16819
16821
  this.reassemble(dataType, msg.subarray(8));
16820
16822
  return;
@@ -16880,9 +16882,11 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
16880
16882
  */
16881
16883
  abandonHole(dataType) {
16882
16884
  const held = this.reorderByType.get(dataType).held;
16883
- if (this.pendingByDataType.has(dataType) && this.tracedDatagramGaps++ < MAX_TRACED_DATAGRAM_GAPS)
16885
+ if ((dataType === P2PDataType.VIDEO || this.pendingByDataType.has(dataType)) && this.tracedDatagramGaps++ < MAX_TRACED_DATAGRAM_GAPS)
16884
16886
  this.trace({ phase: "datagram-gap", dataType });
16885
16887
  this.pendingByDataType.delete(dataType);
16888
+ if (dataType === P2PDataType.VIDEO)
16889
+ this.emit("videoGap");
16886
16890
  const last = this.lastSeqByType.get(dataType);
16887
16891
  const earliest = [...held.keys()].sort((a, b) => (a - last & 65535) - (b - last & 65535))[0];
16888
16892
  this.lastSeqByType.set(dataType, earliest - 1 & 65535);
@@ -17519,7 +17523,8 @@ var AccessUnitAssembler = class {
17519
17523
  * `decode` extracts the payload of a frame, whatever the stream's encryption: it is called for EVERY
17520
17524
  * frame, including a continuation, because a continuation carries its own wrapped key ahead of its share
17521
17525
  * of the payload (measured: 129 bytes beyond what its header declares, exactly as a unit's first frame
17522
- * carries).
17526
+ * carries). A continuation without its matching open unit has no Annex-B start code and cannot be emitted
17527
+ * as a complete unit, even if its repeated header says keyframe.
17523
17528
  */
17524
17529
  push(payload, decode) {
17525
17530
  const header = parseVideoFrameHeader(payload);
@@ -17539,6 +17544,8 @@ var AccessUnitAssembler = class {
17539
17544
  return [unitOf(open2.header, Buffer.concat(open2.chunks))];
17540
17545
  }
17541
17546
  this.discard();
17547
+ if (!beginsAccessUnit(body))
17548
+ return [];
17542
17549
  if (full) {
17543
17550
  this.open = { header, chunks: [body], carried: body.length };
17544
17551
  return [];
@@ -17892,6 +17899,12 @@ var LiveStream = class extends EventEmitter3 {
17892
17899
  lastCodec = "h264";
17893
17900
  /** Rebuilds an access unit the station split across several frames — see {@link AccessUnitAssembler}. */
17894
17901
  units = new AccessUnitAssembler((drop) => this.reportDroppedUnit(drop));
17902
+ /** Whether a missing video datagram or incomplete unit invalidated the current reference chain. */
17903
+ awaitingKeyframeAfterGap = false;
17904
+ videoGapHandler = () => {
17905
+ this.units.discard();
17906
+ this.awaitingKeyframeAfterGap = true;
17907
+ };
17895
17908
  /** The channel inbound media must be tagged with, once {@link acceptsMedia} trusts the station's tag. */
17896
17909
  mediaChannel;
17897
17910
  tracedFirstVideoCommand = false;
@@ -17934,6 +17947,7 @@ var LiveStream = class extends EventEmitter3 {
17934
17947
  return this;
17935
17948
  this.listening = true;
17936
17949
  this.session.on("data", this.handler);
17950
+ this.session.on("videoGap", this.videoGapHandler);
17937
17951
  this.session.on("liveStartUnacknowledged", this.unackedHandler);
17938
17952
  this.sendStart();
17939
17953
  const keepAliveMs = this.opts.keepAliveMs ?? DEFAULT_KEEPALIVE_MS;
@@ -18031,6 +18045,8 @@ var LiveStream = class extends EventEmitter3 {
18031
18045
  return;
18032
18046
  this.listening = false;
18033
18047
  this.session.off("data", this.handler);
18048
+ this.session.off("videoGap", this.videoGapHandler);
18049
+ this.awaitingKeyframeAfterGap = false;
18034
18050
  this.session.off("liveStartUnacknowledged", this.unackedHandler);
18035
18051
  if (this.kaTimer)
18036
18052
  clearInterval(this.kaTimer);
@@ -18066,6 +18082,11 @@ var LiveStream = class extends EventEmitter3 {
18066
18082
  try {
18067
18083
  if (f.commandId === CMD_VIDEO_FRAME2) {
18068
18084
  for (const unit of this.units.push(f.data, (payload) => this.annexbOf(payload, f.signCode))) {
18085
+ if (this.awaitingKeyframeAfterGap) {
18086
+ if (!unit.keyframe)
18087
+ continue;
18088
+ this.awaitingKeyframeAfterGap = false;
18089
+ }
18069
18090
  if (!this.tracedFirstVideoUnit) {
18070
18091
  this.tracedFirstVideoUnit = true;
18071
18092
  this.trace({ phase: "first-video-unit", keyframe: unit.keyframe });
@@ -18160,6 +18181,7 @@ var LiveStream = class extends EventEmitter3 {
18160
18181
  * otherwise silent in both directions: no frame reaches a consumer, and nothing states why.
18161
18182
  */
18162
18183
  reportDroppedUnit(drop) {
18184
+ this.awaitingKeyframeAfterGap = true;
18163
18185
  const message = `[live] dropped an incomplete access unit (${drop.carried} bytes in ${drop.chunks} frame(s), tail never arrived, ${drop.count} so far)`;
18164
18186
  if (drop.count === 1)
18165
18187
  this.logger.warn(message);