@blockcast/mmt-container 2.2.0-main.c3a95413582c → 2.2.0-main.da2e7cd1dd5d

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.
@@ -8754,7 +8754,6 @@ var AMTGatewayManager = class {
8754
8754
  constructor() {
8755
8755
  this.messageHandler = (event) => {
8756
8756
  const data = event.data;
8757
- console.log(`[AMT] SW message received:`, data.type);
8758
8757
  if (data.type === "UDP_PACKET") {
8759
8758
  this.handlePacket(data);
8760
8759
  } else if (data.type === "SOCKET_ERROR") {
@@ -8772,6 +8771,14 @@ var AMTGatewayManager = class {
8772
8771
  this.messageListenerRegistered = true;
8773
8772
  console.log("[AMT] Registered service worker message handler");
8774
8773
  }
8774
+ removeMessageListener() {
8775
+ if (!this.messageListenerRegistered)
8776
+ return;
8777
+ if (this.messageHandler && typeof navigator !== "undefined" && navigator.serviceWorker) {
8778
+ navigator.serviceWorker.removeEventListener("message", this.messageHandler);
8779
+ }
8780
+ this.messageListenerRegistered = false;
8781
+ }
8775
8782
  /**
8776
8783
  * Subscribe via AMT tunnel
8777
8784
  */
@@ -8816,6 +8823,8 @@ var AMTGatewayManager = class {
8816
8823
  this.subscriptions.delete(keyStr);
8817
8824
  this.pendingPackets.delete(subscription.subscriptionId);
8818
8825
  }
8826
+ if (this.subscriptions.size === 0)
8827
+ this.removeMessageListener();
8819
8828
  throw new Error(`Failed to subscribe via AMT: ${error instanceof Error ? error.message : String(error)}`);
8820
8829
  }
8821
8830
  }
@@ -8837,6 +8846,8 @@ var AMTGatewayManager = class {
8837
8846
  } finally {
8838
8847
  this.subscriptions.delete(handle);
8839
8848
  this.pendingPackets.delete(subscription.subscriptionId);
8849
+ if (this.subscriptions.size === 0)
8850
+ this.removeMessageListener();
8840
8851
  }
8841
8852
  }
8842
8853
  /**
@@ -8853,10 +8864,8 @@ var AMTGatewayManager = class {
8853
8864
  if (!subscriptionId)
8854
8865
  return;
8855
8866
  const subscription = this.subscriptions.get(subscriptionId);
8856
- if (!subscription) {
8857
- console.warn(`[AMT] Received packet for unknown subscription: ${subscriptionId}`);
8867
+ if (!subscription)
8858
8868
  return;
8859
- }
8860
8869
  if (!subscription.handshakeComplete) {
8861
8870
  const queue = this.pendingPackets.get(subscriptionId);
8862
8871
  const packetData2 = data;
@@ -8886,20 +8895,15 @@ var AMTGatewayManager = class {
8886
8895
  if (!subscriptionId)
8887
8896
  return;
8888
8897
  const subscription = this.subscriptions.get(subscriptionId);
8889
- if (!subscription) {
8890
- console.warn(`[AMT] Received error for unknown subscription: ${subscriptionId}`);
8898
+ if (!subscription)
8891
8899
  return;
8892
- }
8893
8900
  subscription.config.onError(new Error(error || "Unknown error"));
8894
8901
  }
8895
8902
  /**
8896
8903
  * Cleanup on destroy
8897
8904
  */
8898
8905
  destroy() {
8899
- if (this.messageListenerRegistered && this.messageHandler && typeof navigator !== "undefined" && navigator.serviceWorker) {
8900
- navigator.serviceWorker.removeEventListener("message", this.messageHandler);
8901
- this.messageListenerRegistered = false;
8902
- }
8906
+ this.removeMessageListener();
8903
8907
  const handles = Array.from(this.subscriptions.keys());
8904
8908
  for (const handle of handles) {
8905
8909
  this.unsubscribe(handle).catch((err) => {
@@ -14057,6 +14061,10 @@ var FECManager = class _FECManager {
14057
14061
  // ── Keyframe-protected repair policy (block-policy.ts) ──
14058
14062
  // One classifier per physical stream, built from that stream's geometry.
14059
14063
  this.#classifiers = /* @__PURE__ */ new Map();
14064
+ // A stream without catalog timing has no classifier, so the last RAP it
14065
+ // released stands in for one: "an MPU boundary bounds its RAPs" holds until
14066
+ // a second RAP is released inside one MPU (BLO-52085).
14067
+ this.#noSpanRaps = /* @__PURE__ */ new Map();
14060
14068
  // Geometry a stream-scoped configuration gave one stream (streamKey). ABR
14061
14069
  // rungs can share a packetId with a different framerate or GOP, so the
14062
14070
  // packet-level geometry is only the geometry of a packet whose streams
@@ -14256,6 +14264,7 @@ var FECManager = class _FECManager {
14256
14264
  #orderedFrontiers;
14257
14265
  #orderedPendingBlocks;
14258
14266
  #classifiers;
14267
+ #noSpanRaps;
14259
14268
  #streamGeometries;
14260
14269
  #failedBlocks;
14261
14270
  #resolvedBlockClasses;
@@ -14917,6 +14926,7 @@ var FECManager = class _FECManager {
14917
14926
  };
14918
14927
  const discontinuity = () => {
14919
14928
  this.#classifiers.get(streamKey)?.noteSourceDiscontinuity();
14929
+ this.#noSpanRaps.delete(streamKey);
14920
14930
  this.#highestSbn.set(streamKey, { sbn, atMs: now });
14921
14931
  this.#sourceFrontiers.set(streamKey, { sbn, atMs: now });
14922
14932
  if (psn === void 0) this.#sourceAnchors.delete(streamKey);
@@ -15329,6 +15339,9 @@ var FECManager = class _FECManager {
15329
15339
  }
15330
15340
  if (policyChanged) {
15331
15341
  this.#bumpEpoch(packetId);
15342
+ for (const key of [...this.#noSpanRaps.keys()]) {
15343
+ if (this.#belongsToPacket(key, packetId)) this.#noSpanRaps.delete(key);
15344
+ }
15332
15345
  for (const [key, classifier] of [...this.#classifiers]) {
15333
15346
  if (!this.#belongsToPacket(key, packetId)) continue;
15334
15347
  const stream = this.#parseStreamKey(key);
@@ -15564,6 +15577,7 @@ var FECManager = class _FECManager {
15564
15577
  resetMap(this.#isoLocators);
15565
15578
  resetMap(this.#sourceAnchors);
15566
15579
  this.#classifiers.delete(this.#streamKey(packetId, catalogTrackName));
15580
+ this.#noSpanRaps.delete(this.#streamKey(packetId, catalogTrackName));
15567
15581
  this.#bumpEpoch(packetId);
15568
15582
  for (const [sbn, keys] of this.#blockKeysBySbn) {
15569
15583
  for (const key of keys.keys()) {
@@ -15670,6 +15684,7 @@ var FECManager = class _FECManager {
15670
15684
  dropMap(this.#isoLocators);
15671
15685
  dropMap(this.#sourceAnchors);
15672
15686
  dropMap(this.#classifiers);
15687
+ dropMap(this.#noSpanRaps);
15673
15688
  dropMap(this.#streamGeometries);
15674
15689
  dropSet(this.#pendingWorkerCleanups);
15675
15690
  dropSet(this.#completedBlocks);
@@ -16300,11 +16315,14 @@ var FECManager = class _FECManager {
16300
16315
  /**
16301
16316
  * Whether an MPU boundary still bounds this stream's RAPs (see
16302
16317
  * `BlockClassifier.mpuBoundsRaps`). Gap decisions drop MPU evidence once
16303
- * it does not. A stream with no classifier yet has shown nothing against it.
16318
+ * it does not. A stream with no classifier yet has shown nothing against it,
16319
+ * and neither has a stream without catalog timing until it releases two
16320
+ * RAPs inside one MPU.
16304
16321
  */
16305
16322
  mpuBoundsRapsFor(packetId, catalogTrackName) {
16306
- if (!this.#hasCatalogTimingForPacket(packetId)) return false;
16307
- return this.#classifiers.get(this.#streamKey(packetId, catalogTrackName))?.mpuBoundsRaps ?? true;
16323
+ const streamKey = this.#streamKey(packetId, catalogTrackName);
16324
+ if (!this.#hasCatalogTimingForPacket(packetId)) return this.#noSpanRaps.get(streamKey)?.inside !== true;
16325
+ return this.#classifiers.get(streamKey)?.mpuBoundsRaps ?? true;
16308
16326
  }
16309
16327
  /** A block's class now, or frozen at its resolution. */
16310
16328
  blockClassFor(sbn, packetId, catalogTrackName) {
@@ -16330,7 +16348,14 @@ var FECManager = class _FECManager {
16330
16348
  * invariant (consecutive MPUs exactly one keyframe interval apart).
16331
16349
  */
16332
16350
  noteReleasedRap(packetId, catalogTrackName, mpu, presentationTime, mediaTimescale) {
16333
- if (!this.#trackConfigs.has(packetId) || !this.#hasCatalogTimingForPacket(packetId)) return;
16351
+ if (!this.#trackConfigs.has(packetId)) return;
16352
+ if (!this.#hasCatalogTimingForPacket(packetId)) {
16353
+ const streamKey = this.#streamKey(packetId, catalogTrackName);
16354
+ const last = this.#noSpanRaps.get(streamKey);
16355
+ const inside = last?.inside === true || last?.mpu === mpu && last.presentationTime !== presentationTime;
16356
+ this.#noSpanRaps.set(streamKey, { mpu, presentationTime, inside });
16357
+ return;
16358
+ }
16334
16359
  this.#applyClassifierChanges(
16335
16360
  packetId,
16336
16361
  catalogTrackName,
@@ -17345,6 +17370,7 @@ var FECManager = class _FECManager {
17345
17370
  this.#blockAnchorsMs.clear();
17346
17371
  this.#blockCatalogTrackNames.clear();
17347
17372
  this.#classifiers.clear();
17373
+ this.#noSpanRaps.clear();
17348
17374
  this.#streamGeometries.clear();
17349
17375
  this.#failedBlocks.clear();
17350
17376
  this.#resolvedBlockClasses.clear();
@@ -19386,6 +19412,10 @@ var MmtpContainerParser = class _MmtpContainerParser {
19386
19412
  }
19387
19413
  this.#emitFrame(data, meta);
19388
19414
  }
19415
+ /** Whether FT=1 metadata already names this sample, without claiming it. */
19416
+ hasAuthoredTimingFor(packetId, mpuSequenceNumber2, movieFragmentSequenceNumber, sampleNumber, catalogTrackName) {
19417
+ return this.#timingResolver(this.#streamKey(packetId, catalogTrackName), packetId, false)?.sampleTiming(mpuSequenceNumber2, movieFragmentSequenceNumber, sampleNumber) != null;
19418
+ }
19389
19419
  /**
19390
19420
  * Claim and return the authored timing for a recovered sample. Recovery does
19391
19421
  * not pass through the ordinary `feed()` completion path, so it must retire
@@ -25910,6 +25940,16 @@ var MmtpRouter = class {
25910
25940
  }
25911
25941
  );
25912
25942
  }
25943
+ result = {
25944
+ ...result,
25945
+ symbols: result.symbols.filter((sym) => sym.fragmentType !== 2 || sym.fragment.fragmentationIndicator !== 1 || sym.fragment.movieFragmentSequenceNumber === void 0 || sym.fragment.sampleNumber === void 0 || this.#parser.hasAuthoredTimingFor(
25946
+ ownerPacketId,
25947
+ sym.fragment.mpuSequenceNumber,
25948
+ sym.fragment.movieFragmentSequenceNumber,
25949
+ sym.fragment.sampleNumber,
25950
+ catalogTrackName
25951
+ ))
25952
+ };
25913
25953
  const gated = this.#isFecTrack(ownerPacketId);
25914
25954
  const assembler = this.#mseAssemblerFor(ownerPacketId, catalogTrackName);
25915
25955
  if (assembler) {