@blockcast/mmt-container 2.2.0-main.0f6aad7bb803 → 2.2.0-main.20c61ec37932

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.
@@ -31487,6 +31487,19 @@ function resolveRepairLayers(catalog, source) {
31487
31487
  totalBaseRepairSymbols: binding.totalBaseRepairSymbols
31488
31488
  };
31489
31489
  }
31490
+ function valueAt(catalog, pointer) {
31491
+ let node = catalog;
31492
+ for (const segment of pointer.split("/").slice(1)) {
31493
+ if (typeof node !== "object" || node === null) return void 0;
31494
+ node = node[segment.replace(/~1/g, "/").replace(/~0/g, "~")];
31495
+ }
31496
+ return node;
31497
+ }
31498
+ function catalogTrackDeliveryMode(catalog, source) {
31499
+ const binding = bindingOf(catalog, source);
31500
+ const entry = binding ? valueAt(catalog, binding.pointer) : void 0;
31501
+ return entry?.deliveryMode === "stream" ? "stream" : "datagram";
31502
+ }
31490
31503
  function moqtPriority2(value) {
31491
31504
  return Number.isSafeInteger(value) && value >= 0 && value <= 255 ? value : null;
31492
31505
  }
@@ -31530,6 +31543,7 @@ function fecParams(catalog, track, fps, sampleRate) {
31530
31543
  repairTrackName: base.repairTrack,
31531
31544
  repairLayers: repair.baseLayers,
31532
31545
  repairOverlays: repair.overlays,
31546
+ deliveryMode: catalogTrackDeliveryMode(catalog, track),
31533
31547
  ...mediaRate
31534
31548
  };
31535
31549
  }
@@ -32019,6 +32033,168 @@ function requireNumber(value, path) {
32019
32033
  return value;
32020
32034
  }
32021
32035
 
32036
+ // src/repair-layer-subscriptions.ts
32037
+ var SERIAL32_HALF2 = 2147483648;
32038
+ var RepairLayerSubscriptions = class {
32039
+ #opts;
32040
+ #windowPackets;
32041
+ #margin;
32042
+ #dropAfterWindows;
32043
+ #source;
32044
+ #layerCount = 0;
32045
+ #subs = /* @__PURE__ */ new Map();
32046
+ #disposed = false;
32047
+ #lastSeq;
32048
+ #expected = 0;
32049
+ #lost = 0;
32050
+ #wantFewer = 0;
32051
+ #lossRate = null;
32052
+ #repairPackets = 0;
32053
+ #repairBytes = 0;
32054
+ #staleDropped = 0;
32055
+ constructor(opts) {
32056
+ this.#opts = opts;
32057
+ this.#source = opts.source;
32058
+ this.#windowPackets = opts.windowPackets ?? 500;
32059
+ this.#margin = opts.margin ?? 2;
32060
+ this.#dropAfterWindows = opts.dropAfterWindows ?? 3;
32061
+ }
32062
+ get layerCount() {
32063
+ return this.#layerCount;
32064
+ }
32065
+ /**
32066
+ * One source packet's MMTP `packet_sequence_number`, in arrival order.
32067
+ * The sequence is per `packet_id`: pass the packets of ONE packet_id only,
32068
+ * or interleaved sequences read as loss.
32069
+ */
32070
+ noteSourceSequence(seq) {
32071
+ if (this.#disposed || this.#delivery() === "stream") return;
32072
+ seq >>>= 0;
32073
+ if (this.#lastSeq === void 0) {
32074
+ this.#lastSeq = seq;
32075
+ return;
32076
+ }
32077
+ const d = serial32Distance(this.#lastSeq, seq);
32078
+ if (d === 0) return;
32079
+ const back = d >= SERIAL32_HALF2 ? 2 ** 32 - d : 0;
32080
+ if (d > this.#windowPackets && (back === 0 || back > this.#windowPackets)) {
32081
+ this.#lastSeq = seq;
32082
+ this.#expected = 0;
32083
+ this.#lost = 0;
32084
+ return;
32085
+ }
32086
+ if (back === 0) {
32087
+ this.#expected += d;
32088
+ this.#lost += d - 1;
32089
+ this.#lastSeq = seq;
32090
+ } else if (this.#lost > 0) {
32091
+ this.#lost -= 1;
32092
+ }
32093
+ if (this.#expected >= this.#windowPackets) this.#closeWindow();
32094
+ }
32095
+ /** ABR switch R -> R': close R's tracks, carry the layer count to R'. */
32096
+ switchSource(next) {
32097
+ if (this.#disposed) return;
32098
+ this.#closeAll();
32099
+ this.#source = next;
32100
+ this.#lastSeq = void 0;
32101
+ this.#expected = 0;
32102
+ this.#lost = 0;
32103
+ this.#wantFewer = 0;
32104
+ this.#layerCount = this.#delivery() === "stream" ? 0 : Math.min(this.#layerCount, this.#layers().length);
32105
+ this.#reconcile();
32106
+ }
32107
+ snapshot() {
32108
+ return {
32109
+ delivery: this.#delivery(),
32110
+ layerCount: this.#layerCount,
32111
+ subscribedTracks: [...this.#subs.keys()],
32112
+ repairPackets: this.#repairPackets,
32113
+ repairBytes: this.#repairBytes,
32114
+ staleDropped: this.#staleDropped,
32115
+ lossRate: this.#lossRate
32116
+ };
32117
+ }
32118
+ dispose() {
32119
+ if (this.#disposed) return;
32120
+ this.#closeAll();
32121
+ this.#disposed = true;
32122
+ }
32123
+ #delivery() {
32124
+ return this.#source.deliveryMode === "stream" ? "stream" : "datagram";
32125
+ }
32126
+ #layers() {
32127
+ return this.#source.repairLayers ?? [];
32128
+ }
32129
+ #closeWindow() {
32130
+ const rate = this.#lost / this.#expected;
32131
+ this.#lossRate = rate;
32132
+ this.#expected = 0;
32133
+ this.#lost = 0;
32134
+ const target = this.#targetLayers(rate);
32135
+ if (target > this.#layerCount) {
32136
+ this.#wantFewer = 0;
32137
+ this.#layerCount = target;
32138
+ } else if (target < this.#layerCount) {
32139
+ this.#wantFewer += 1;
32140
+ if (this.#wantFewer >= this.#dropAfterWindows) {
32141
+ this.#wantFewer = 0;
32142
+ this.#layerCount -= 1;
32143
+ }
32144
+ } else {
32145
+ this.#wantFewer = 0;
32146
+ }
32147
+ this.#reconcile();
32148
+ }
32149
+ /** Fewest base layers whose summed P covers margin x the measured loss of K. */
32150
+ #targetLayers(rate) {
32151
+ if (rate <= 0) return 0;
32152
+ const needed = Math.ceil(rate * this.#source.fecK * this.#margin);
32153
+ const layers = this.#layers();
32154
+ let held = 0;
32155
+ for (let n = 0; n < layers.length; n++) {
32156
+ held += layers[n].repairSymbols;
32157
+ if (held >= needed) return n + 1;
32158
+ }
32159
+ return layers.length;
32160
+ }
32161
+ /** Stream delivery never leaves layer count 0, so it never subscribes. */
32162
+ #reconcile() {
32163
+ const want = /* @__PURE__ */ new Map();
32164
+ for (const layer of this.#layers().slice(0, this.#layerCount)) {
32165
+ want.set(layer.repairTrackName, layer.priority);
32166
+ }
32167
+ const overlay = this.#source.repairOverlays?.[0];
32168
+ if (this.#layerCount > 0 && overlay) want.set(overlay.repairTrackName, overlay.priority);
32169
+ for (const [name, entry] of this.#subs) {
32170
+ if (!want.has(name)) {
32171
+ entry.sub.close();
32172
+ this.#subs.delete(name);
32173
+ }
32174
+ }
32175
+ for (const [name, priority] of want) {
32176
+ if (this.#subs.has(name)) continue;
32177
+ const entry = {};
32178
+ entry.sub = this.#opts.subscribe(name, priority, (packet) => this.#onPacket(name, entry, packet));
32179
+ this.#subs.set(name, entry);
32180
+ }
32181
+ }
32182
+ /** Fenced on the entry itself, so a closed subscription is stale even if its track is re-added. */
32183
+ #onPacket(name, entry, packet) {
32184
+ if (this.#disposed || this.#subs.get(name) !== entry) {
32185
+ this.#staleDropped += 1;
32186
+ return;
32187
+ }
32188
+ this.#repairPackets += 1;
32189
+ this.#repairBytes += packet.byteLength;
32190
+ this.#opts.feed(packet, name);
32191
+ }
32192
+ #closeAll() {
32193
+ for (const entry of this.#subs.values()) entry.sub.close();
32194
+ this.#subs.clear();
32195
+ }
32196
+ };
32197
+
32022
32198
  // src/repair-fetch.ts
32023
32199
  var MOQT_PRIORITY_MAX = 255;
32024
32200
  var SOURCE_MEDIA_PRIORITY_MAX = REPAIR_PRIORITY_MIN - 1;
@@ -32664,6 +32840,7 @@ export {
32664
32840
  REPAIR_LIFECYCLE_LOG_PREFIX,
32665
32841
  REPAIR_PRIORITY_MAX,
32666
32842
  REPAIR_PRIORITY_MIN,
32843
+ RepairLayerSubscriptions,
32667
32844
  SOURCE_MEDIA_PRIORITY_MAX,
32668
32845
  SampleCombineError,
32669
32846
  SampleCombiner,
@@ -32688,6 +32865,7 @@ export {
32688
32865
  catalogGroupDurationMs,
32689
32866
  catalogKeyframeCadenceMs,
32690
32867
  catalogRepairTarget,
32868
+ catalogTrackDeliveryMode,
32691
32869
  catalogTrackFecUnavailable,
32692
32870
  classifyH264Keyframe,
32693
32871
  classifyHevcKeyframe,