@blockcast/mmt-container 2.2.0-main.75b39a2cdddf → 2.2.0-main.7e8a9d13c01c

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.
Files changed (52) hide show
  1. package/dist/browser-runtime.js +634 -129
  2. package/dist/browser-runtime.js.map +3 -3
  3. package/dist/delta-fallback-config.js.map +1 -1
  4. package/dist/fec-manager.d.ts +37 -11
  5. package/dist/fec-manager.d.ts.map +1 -1
  6. package/dist/fec-manager.js +181 -52
  7. package/dist/fec-manager.js.map +2 -2
  8. package/dist/fec-worker-setup.js.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js.map +2 -2
  12. package/dist/iso-block-locator.d.ts +39 -13
  13. package/dist/iso-block-locator.d.ts.map +1 -1
  14. package/dist/iso-block-locator.js +80 -25
  15. package/dist/iso-block-locator.js.map +2 -2
  16. package/dist/media-router.js.map +1 -1
  17. package/dist/mmtp-container-parser.d.ts +21 -0
  18. package/dist/mmtp-container-parser.d.ts.map +1 -1
  19. package/dist/mmtp-container-parser.js +114 -11
  20. package/dist/mmtp-container-parser.js.map +2 -2
  21. package/dist/mmtp-container-parser.no-modules.js +113 -12
  22. package/dist/mmtp-container-parser.no-modules.js.map +2 -2
  23. package/dist/mmtp-decode-pipeline.js +114 -11
  24. package/dist/mmtp-decode-pipeline.js.map +2 -2
  25. package/dist/mmtp-router.d.ts +18 -9
  26. package/dist/mmtp-router.d.ts.map +1 -1
  27. package/dist/mmtp-router.js +254 -44
  28. package/dist/mmtp-router.js.map +2 -2
  29. package/dist/multicast-manager.d.ts +13 -3
  30. package/dist/multicast-manager.d.ts.map +1 -1
  31. package/dist/multicast-manager.js +455 -103
  32. package/dist/multicast-manager.js.map +2 -2
  33. package/dist/no-modules.js +114 -11
  34. package/dist/no-modules.js.map +2 -2
  35. package/dist/repair-fetch.d.ts +36 -8
  36. package/dist/repair-fetch.d.ts.map +1 -1
  37. package/dist/repair-fetch.js +285 -26
  38. package/dist/repair-fetch.js.map +3 -3
  39. package/dist/track-session.d.ts.map +1 -1
  40. package/dist/track-session.js +1 -0
  41. package/dist/track-session.js.map +2 -2
  42. package/dist/wasm-mmtp-container-parser.js +114 -11
  43. package/dist/wasm-mmtp-container-parser.js.map +2 -2
  44. package/package.json +5 -5
  45. package/src/fec-manager.ts +156 -26
  46. package/src/index.ts +2 -0
  47. package/src/iso-block-locator.ts +114 -31
  48. package/src/mmtp-container-parser.ts +181 -10
  49. package/src/mmtp-router.ts +231 -58
  50. package/src/multicast-manager.ts +44 -6
  51. package/src/repair-fetch.ts +363 -49
  52. package/src/track-session.ts +3 -0
@@ -6005,7 +6005,10 @@ var BlockcastMmt = (() => {
6005
6005
  function ssIdAfter(a, b) {
6006
6006
  return (a - b | 0) > 0;
6007
6007
  }
6008
- var _streams2, _gate, _emit2, _recordStat2, _deferDepth, _deferredStreams, _FecReleaseSequencer_instances, drainUnlessDeferred_fn, streamFor_fn2, drain_fn, release_fn;
6008
+ function holdsRebuilt(stream) {
6009
+ return stream.buf.some(({ meta }) => meta.fecSbnFirst !== void 0);
6010
+ }
6011
+ var _streams2, _gate, _emit2, _recordStat2, _deferDepth, _deferredStreams, _FecReleaseSequencer_instances, drainUnlessDeferred_fn, streamFor_fn2, drain_fn, drainLoop_fn, cursorPassed_fn, release_fn;
6009
6012
  var FecReleaseSequencer = class {
6010
6013
  constructor(gate, emit, recordStat) {
6011
6014
  __privateAdd(this, _FecReleaseSequencer_instances);
@@ -6065,6 +6068,7 @@ var BlockcastMmt = (() => {
6065
6068
  stream.lastSbn = void 0;
6066
6069
  stream.discontinuity = false;
6067
6070
  stream.rapSsId = void 0;
6071
+ stream.sourced = false;
6068
6072
  }
6069
6073
  if (stream.last !== null && compareFrameOrder(frame, stream.last) <= 0) {
6070
6074
  __privateGet(this, _recordStat2).call(this, "droppedStale");
@@ -6091,6 +6095,7 @@ var BlockcastMmt = (() => {
6091
6095
  if (compareFrameOrder(stream.buf[mid], frame) < 0) lo = mid + 1;
6092
6096
  else hi = mid;
6093
6097
  }
6098
+ if (stream.buf[lo]?.passed === true) frame.passed = true;
6094
6099
  stream.buf.splice(lo, 0, frame);
6095
6100
  __privateMethod(this, _FecReleaseSequencer_instances, drainUnlessDeferred_fn).call(this, stream);
6096
6101
  }
@@ -6126,6 +6131,41 @@ var BlockcastMmt = (() => {
6126
6131
  }
6127
6132
  return false;
6128
6133
  }
6134
+ /**
6135
+ * These streams' sink is being replaced by one that has seen no source
6136
+ * frame yet. First, from a stream that holds a frame the overlay rebuilt,
6137
+ * release to the sink being replaced the frames the unanchored path had
6138
+ * already released to it (#cursorPassed): there they waited in its queue,
6139
+ * which its replacement flushes. A stream that holds none is not drained:
6140
+ * it holds nothing the anchor kept back, and a drain would still force out
6141
+ * a frame held past the hold limit, which before the anchor waited for the
6142
+ * next push. Then treat the streams as unsourced until a source frame is
6143
+ * released.
6144
+ */
6145
+ unsource(packetId, catalogTrackName) {
6146
+ for (const stream of __privateGet(this, _streams2).values()) {
6147
+ if (stream.packetId === packetId && (catalogTrackName === void 0 || stream.catalogTrackName === catalogTrackName)) {
6148
+ if (stream.draining === 0 && holdsRebuilt(stream)) {
6149
+ if (__privateGet(this, _deferDepth) > 0) __privateGet(this, _deferredStreams).add(stream);
6150
+ else __privateMethod(this, _FecReleaseSequencer_instances, drain_fn).call(this, stream, true);
6151
+ }
6152
+ stream.sourced = false;
6153
+ }
6154
+ }
6155
+ }
6156
+ /**
6157
+ * Whether a stream of `packetId` holds a frame the keyframe overlay rebuilt
6158
+ * (FrameMeta.fecSbnFirst). Without `catalogTrackName`, every stream of the
6159
+ * packetId.
6160
+ */
6161
+ holdsRebuilt(packetId, catalogTrackName) {
6162
+ for (const stream of __privateGet(this, _streams2).values()) {
6163
+ if (stream.packetId !== packetId) continue;
6164
+ if (catalogTrackName !== void 0 && stream.catalogTrackName !== catalogTrackName) continue;
6165
+ if (holdsRebuilt(stream)) return true;
6166
+ }
6167
+ return false;
6168
+ }
6129
6169
  /** Re-evaluate held gaps after FEC state changed. */
6130
6170
  poke(streamKey) {
6131
6171
  if (streamKey !== void 0) {
@@ -6229,16 +6269,32 @@ var BlockcastMmt = (() => {
6229
6269
  last: null,
6230
6270
  lastSbn: void 0,
6231
6271
  discontinuity: false,
6232
- rapSsId: void 0
6272
+ rapSsId: void 0,
6273
+ sourced: false,
6274
+ draining: 0
6233
6275
  };
6234
6276
  __privateGet(this, _streams2).set(streamKey, stream);
6235
6277
  }
6236
6278
  return stream;
6237
6279
  };
6238
- drain_fn = function(stream) {
6280
+ /** `asUnanchored`: release overlay-rebuilt frames when unanchored did (#cursorPassed). */
6281
+ drain_fn = function(stream, asUnanchored = false) {
6282
+ stream.draining++;
6283
+ try {
6284
+ __privateMethod(this, _FecReleaseSequencer_instances, drainLoop_fn).call(this, stream, asUnanchored);
6285
+ } finally {
6286
+ stream.draining--;
6287
+ }
6288
+ };
6289
+ drainLoop_fn = function(stream, asUnanchored) {
6239
6290
  while (stream.buf.length > 0 && stream.last !== null) {
6240
6291
  const head = stream.buf[0];
6241
6292
  const last = stream.last;
6293
+ if (compareFrameOrder(head, last) <= 0) {
6294
+ stream.buf.shift();
6295
+ __privateMethod(this, _FecReleaseSequencer_instances, release_fn).call(this, stream, head, void 0);
6296
+ continue;
6297
+ }
6242
6298
  if (stream.discontinuity) {
6243
6299
  stream.discontinuity = false;
6244
6300
  stream.buf.shift();
@@ -6252,9 +6308,10 @@ var BlockcastMmt = (() => {
6252
6308
  }
6253
6309
  const headSbn = head.meta.fecSbn;
6254
6310
  const from = stream.lastSbn ?? headSbn;
6255
- const to = headSbn ?? stream.lastSbn;
6311
+ const to = head.meta.fecSbnFirst ?? headSbn ?? stream.lastSbn;
6256
6312
  let lost = [];
6257
6313
  const unanchored = from === void 0 && to === void 0;
6314
+ let unresolved = false;
6258
6315
  if (from !== void 0 && to !== void 0) {
6259
6316
  const resolved = __privateGet(this, _gate).resolvedLoss(
6260
6317
  stream.packetId,
@@ -6263,7 +6320,8 @@ var BlockcastMmt = (() => {
6263
6320
  Math.max(from, to),
6264
6321
  from
6265
6322
  );
6266
- if (resolved === null) {
6323
+ unresolved = resolved === null;
6324
+ if (unresolved && !__privateMethod(this, _FecReleaseSequencer_instances, cursorPassed_fn).call(this, stream, asUnanchored)) {
6267
6325
  const heldMs = performance.now() - head.arrivedAtMs;
6268
6326
  if (heldMs <= __privateGet(this, _gate).holdLimitMs(stream.packetId, stream.catalogTrackName)) return;
6269
6327
  __privateGet(this, _recordStat2).call(this, "forcedWindowFlushes");
@@ -6271,18 +6329,52 @@ var BlockcastMmt = (() => {
6271
6329
  __privateMethod(this, _FecReleaseSequencer_instances, release_fn).call(this, stream, head, __privateGet(this, _gate).decide(last, head, [], true));
6272
6330
  continue;
6273
6331
  }
6274
- lost = resolved;
6332
+ lost = resolved ?? [];
6275
6333
  }
6276
6334
  stream.buf.shift();
6277
- __privateMethod(this, _FecReleaseSequencer_instances, release_fn).call(this, stream, head, lost.length > 0 || unanchored || authoredGap(last.meta, head.meta) ? __privateGet(this, _gate).decide(last, head, lost, false) : void 0);
6335
+ __privateMethod(this, _FecReleaseSequencer_instances, release_fn).call(this, stream, head, lost.length > 0 || unanchored || unresolved || authoredGap(last.meta, head.meta) ? __privateGet(this, _gate).decide(last, head, lost, false) : void 0);
6278
6336
  }
6279
6337
  };
6338
+ /**
6339
+ * An overlay-rebuilt frame (fecSbnFirst) waits no longer than the BLO-53342
6340
+ * source cursor holds it unanchored, and neither does a later frame behind
6341
+ * it. Unanchored, a frame that waits on no block (fecSbnFirst set, or no
6342
+ * fecSbn) left the gate once every frame ahead of it had: mark it `passed`,
6343
+ * like each frame that arrived in front of it since (stale there). The head
6344
+ * then goes, decided as it would be unanchored, once a frame the base path
6345
+ * delivered (a source frame, or one base FEC recovered) is buffered after a
6346
+ * marked one: the base path has passed that one, so a frame still missing
6347
+ * before it can only come from a repair. It also goes while no source frame
6348
+ * has been released, when the direct path shows a recovered frame at once.
6349
+ * And it goes at once while a staged switch decides on when frames arrive
6350
+ * (FecReleaseGate.releaseUnanchored), and when unsource releases into a
6351
+ * sink being replaced: unanchored, it had already reached the sink.
6352
+ * The scan also writes: the `passed` marks it sets stay on the frames,
6353
+ * and push marks a frame it inserts in front of a marked one from them.
6354
+ */
6355
+ cursorPassed_fn = function(stream, asUnanchored) {
6356
+ let at = -1;
6357
+ for (let i = 0; i < stream.buf.length; i++) {
6358
+ const frame = stream.buf[i];
6359
+ if (frame.meta.fecSbnFirst !== void 0 || frame.meta.fecSbn === void 0) {
6360
+ frame.passed = true;
6361
+ if (at < 0) at = i;
6362
+ } else if (frame.passed !== true) break;
6363
+ }
6364
+ if (at < 0) return false;
6365
+ return asUnanchored || !stream.sourced || __privateGet(this, _gate).releaseUnanchored?.(stream.packetId, stream.catalogTrackName) === true || stream.buf.some(({ meta }, i) => i > at && meta.fecSbnFirst === void 0 && (meta.recovered !== true || meta.fecSbn !== void 0));
6366
+ };
6280
6367
  release_fn = function(stream, frame, decision) {
6368
+ const stale = stream.last !== null && compareFrameOrder(frame, stream.last) <= 0;
6369
+ if (stale) __privateGet(this, _recordStat2).call(this, "droppedStale");
6281
6370
  if (decision) frame.meta.gapBefore = decision;
6282
6371
  stream.last = frame;
6283
- if (frame.meta.fecSbn !== void 0) stream.lastSbn = frame.meta.fecSbn;
6372
+ if (frame.meta.fecSbn !== void 0 && (frame.meta.fecSbnFirst === void 0 || stream.lastSbn !== void 0)) {
6373
+ stream.lastSbn = frame.meta.fecSbn;
6374
+ }
6375
+ if (frame.meta.recovered !== true) stream.sourced = true;
6284
6376
  __privateGet(this, _gate).onReleased?.(frame.data, frame.meta);
6285
- __privateGet(this, _emit2).call(this, frame.data, frame.meta);
6377
+ if (!stale) __privateGet(this, _emit2).call(this, frame.data, frame.meta);
6286
6378
  };
6287
6379
  var FMPU_BOX_TYPES = /* @__PURE__ */ new Set(["ftyp", "moov", "moof"]);
6288
6380
  function isFmp4Box(data) {
@@ -6525,6 +6617,14 @@ var BlockcastMmt = (() => {
6525
6617
  fecReleaseRapAbove(packetId, catalogTrackName, ssId) {
6526
6618
  return __privateGet(this, _fecSequencer)?.rapAbove(packetId, catalogTrackName, ssId) ?? false;
6527
6619
  }
6620
+ /** See FecReleaseSequencer.unsource. */
6621
+ unsourceFecRelease(packetId, catalogTrackName) {
6622
+ __privateGet(this, _fecSequencer)?.unsource(packetId, catalogTrackName);
6623
+ }
6624
+ /** See FecReleaseSequencer.holdsRebuilt. */
6625
+ fecReleaseHoldsRebuilt(packetId, catalogTrackName) {
6626
+ return __privateGet(this, _fecSequencer)?.holdsRebuilt(packetId, catalogTrackName) ?? false;
6627
+ }
6528
6628
  /** Re-evaluate held gaps after FEC block state changed. */
6529
6629
  pokeFecRelease(packetId, catalogTrackName) {
6530
6630
  if (!__privateGet(this, _fecSequencer)) return;
@@ -7149,7 +7249,7 @@ var BlockcastMmt = (() => {
7149
7249
  headTiming.size
7150
7250
  );
7151
7251
  if (readyOnRegister) {
7152
- const deferred = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, readyOnRegister, info, resolver, options?.recovered === true, options?.fecSbn);
7252
+ const deferred = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, readyOnRegister, info, resolver, options?.recovered === true, options?.fecSbn, options?.fecSbnFirst);
7153
7253
  if (deferred.record === void 0) __privateMethod(this, _MmtpContainerParser_instances, countDeferredOutcome_fn).call(this, deferred.reason);
7154
7254
  }
7155
7255
  }
@@ -7236,7 +7336,7 @@ var BlockcastMmt = (() => {
7236
7336
  fragmentCounter: mpu.fragmentCounter
7237
7337
  };
7238
7338
  }
7239
- const outcome = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, combined, info, resolver, options?.recovered === true, options?.fecSbn);
7339
+ const outcome = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, combined, info, resolver, options?.recovered === true, options?.fecSbn, options?.fecSbnFirst);
7240
7340
  if (outcome.record !== void 0) return outcome.record;
7241
7341
  return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, outcome.reason);
7242
7342
  };
@@ -7255,7 +7355,7 @@ var BlockcastMmt = (() => {
7255
7355
  * attribution exists to keep readable. Leaving the choice at the call site
7256
7356
  * is what keeps both true.
7257
7357
  */
7258
- emitCombinedSample_fn = function(combined, info, resolver, recovered, fecSbn) {
7358
+ emitCombinedSample_fn = function(combined, info, resolver, recovered, fecSbn, fecSbnFirst) {
7259
7359
  const timing = resolver.sampleTiming(
7260
7360
  combined.mpuSequenceNumber,
7261
7361
  combined.movieFragmentSequenceNumber,
@@ -7266,6 +7366,7 @@ var BlockcastMmt = (() => {
7266
7366
  const meta = __privateMethod(this, _MmtpContainerParser_instances, buildFrameMeta_fn).call(this, combined, info.packetId, info.sequenceNumber, timing, recovered);
7267
7367
  if (!meta) return { reason: "combined-meta-build-failed" };
7268
7368
  if (fecSbn !== void 0) meta.fecSbn = fecSbn;
7369
+ if (fecSbnFirst !== void 0) meta.fecSbnFirst = fecSbnFirst;
7269
7370
  if (!resolver.consumeSample(
7270
7371
  combined.mpuSequenceNumber,
7271
7372
  combined.movieFragmentSequenceNumber,