@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.
- package/dist/browser-runtime.js +178 -0
- package/dist/browser-runtime.js.map +4 -4
- package/dist/catalog-fec-params.d.ts +16 -0
- package/dist/catalog-fec-params.d.ts.map +1 -1
- package/dist/catalog-fec-params.js +15 -0
- package/dist/catalog-fec-params.js.map +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +2 -2
- package/dist/repair-layer-subscriptions.d.ts +82 -0
- package/dist/repair-layer-subscriptions.d.ts.map +1 -0
- package/dist/repair-layer-subscriptions.js +192 -0
- package/dist/repair-layer-subscriptions.js.map +7 -0
- package/package.json +5 -5
- package/schemas/catalog.schema.json +4 -0
- package/src/catalog-fec-params.ts +35 -0
- package/src/index.ts +10 -0
- package/src/repair-layer-subscriptions.ts +261 -0
package/dist/browser-runtime.js
CHANGED
|
@@ -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,
|