@blockcast/mmt-container 2.2.0-main.efb4fa4521af → 2.2.0-main.fb5c7dfbe2de
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/README.md +29 -17
- package/dist/browser-runtime.js +1336 -302
- package/dist/browser-runtime.js.map +3 -3
- package/dist/catalog-fec-params.d.ts +17 -1
- 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/cmcd-producer.d.ts +60 -47
- package/dist/cmcd-producer.d.ts.map +1 -1
- package/dist/cmcd-producer.js +138 -109
- package/dist/cmcd-producer.js.map +2 -2
- package/dist/delivery-catalog.js +26 -16
- package/dist/delivery-catalog.js.map +2 -2
- package/dist/delta-fallback-config.js.map +1 -1
- package/dist/fec-manager.d.ts +70 -12
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +403 -58
- package/dist/fec-manager.js.map +2 -2
- package/dist/fec-worker-setup.d.ts +1 -1
- package/dist/fec-worker-setup.js +1 -1
- package/dist/fec-worker-setup.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +2 -2
- package/dist/iso-block-locator.d.ts +48 -13
- package/dist/iso-block-locator.d.ts.map +1 -1
- package/dist/iso-block-locator.js +97 -25
- package/dist/iso-block-locator.js.map +2 -2
- package/dist/iso-bmff-timing.d.ts +10 -1
- package/dist/iso-bmff-timing.d.ts.map +1 -1
- package/dist/iso-bmff-timing.js +36 -2
- package/dist/iso-bmff-timing.js.map +2 -2
- package/dist/media-router.js.map +1 -1
- package/dist/mmtp-container-parser.d.ts +79 -10
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +207 -26
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +209 -29
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +206 -26
- package/dist/mmtp-decode-pipeline.js.map +2 -2
- package/dist/mmtp-router.d.ts +34 -8
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +555 -79
- package/dist/mmtp-router.js.map +2 -2
- package/dist/multicast-manager.d.ts +13 -3
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +980 -146
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.js +28 -18
- package/dist/multicast-transport.js.map +2 -2
- package/dist/no-modules.js +206 -26
- package/dist/no-modules.js.map +2 -2
- package/dist/repair-fetch.d.ts +36 -8
- package/dist/repair-fetch.d.ts.map +1 -1
- package/dist/repair-fetch.js +285 -26
- package/dist/repair-fetch.js.map +3 -3
- package/dist/repair-layer-subscriptions.d.ts +6 -2
- package/dist/repair-layer-subscriptions.d.ts.map +1 -1
- package/dist/repair-layer-subscriptions.js +6 -3
- package/dist/repair-layer-subscriptions.js.map +2 -2
- package/dist/track-session.d.ts +1 -1
- package/dist/track-session.d.ts.map +1 -1
- package/dist/track-session.js +1 -0
- package/dist/track-session.js.map +2 -2
- package/dist/wasm-mmtp-container-parser.js +206 -26
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/package.json +8 -5
- package/src/catalog-fec-params.ts +36 -1
- package/src/cmcd-producer.ts +189 -179
- package/src/fec-manager.ts +433 -32
- package/src/fec-worker-setup.ts +2 -2
- package/src/index.ts +9 -2
- package/src/iso-block-locator.ts +133 -31
- package/src/iso-bmff-timing.ts +40 -1
- package/src/mmtp-container-parser.ts +306 -29
- package/src/mmtp-router.ts +548 -38
- package/src/multicast-manager.ts +44 -6
- package/src/repair-fetch.ts +363 -49
- package/src/repair-layer-subscriptions.ts +13 -5
- package/src/track-session.ts +4 -1
package/dist/repair-fetch.d.ts
CHANGED
|
@@ -41,6 +41,18 @@
|
|
|
41
41
|
* or otherwise never sent cancels nothing (§11.4.5 item 3), and an audio
|
|
42
42
|
* request never preempts. A P2 that never ran before its block resolved
|
|
43
43
|
* is reported as `repair-deferred`.
|
|
44
|
+
* - A hole walked over the one-Group transport (no `rangeTransport`) is
|
|
45
|
+
* repair the run gets before its FEC deadline (`walkHole`). On a video
|
|
46
|
+
* track it is keyframe repair (class `unknown`): P0, and no audio or
|
|
47
|
+
* delta FETCH is issued while one of its Group FETCHes is outstanding
|
|
48
|
+
* (fec-multicast-00 rule 3). It reaches no FEC deadline, so it preempts
|
|
49
|
+
* nothing and holds back no audio or delta request: one that comes due
|
|
50
|
+
* cancels the walk's Group FETCH and goes out at once, and the walk asks
|
|
51
|
+
* for that Group again after it (`yieldVideoWalks`). On an audio track
|
|
52
|
+
* it is audio repair: P1 at the audio wire priority, one Group per FETCH,
|
|
53
|
+
* and like any audio request it waits while keyframe repair is
|
|
54
|
+
* outstanding, stopping before its next Group, and is preempted by a
|
|
55
|
+
* keyframe FETCH sent.
|
|
44
56
|
* - A block reclassified to a higher class while its P2 fetch is in flight
|
|
45
57
|
* is re-issued at once under the new class's wire priority: the running
|
|
46
58
|
* FETCH is aborted (FETCH_CANCEL) and a new one sent.
|
|
@@ -101,8 +113,8 @@
|
|
|
101
113
|
*/
|
|
102
114
|
import { type FecBlockProfile } from '@blockcast/mmt-base';
|
|
103
115
|
import { type RepairFetchRange } from '@blockcast/mmt-fec';
|
|
104
|
-
import { type BlockClass, type ClassifierMode, type RepairPriority } from './block-policy.js';
|
|
105
|
-
import type { UndelimitedIsoLoss } from './fec-manager.js';
|
|
116
|
+
import { type BlockClass, type ClassifierMode, type RepairPriority, type TrackKind } from './block-policy.js';
|
|
117
|
+
import type { ExpiredIsoHole, UndelimitedIsoLoss } from './fec-manager.js';
|
|
106
118
|
import type { RepairLifecycleObserver } from './multicast-manager.js';
|
|
107
119
|
/**
|
|
108
120
|
* The highest value in the Source Media priority range of
|
|
@@ -322,10 +334,14 @@ export interface WireRepairFetchOptions {
|
|
|
322
334
|
keyframeRepairBudgetMs?: (packetId: number, catalogTrackName?: string) => number;
|
|
323
335
|
/**
|
|
324
336
|
* Range repair for a lost SS_ID whose block no repair delimited
|
|
325
|
-
* (draft-ramadan-moq-fec §7.5), optional.
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
337
|
+
* (draft-ramadan-moq-fec §7.5), optional. A host that can keep such a gap as
|
|
338
|
+
* a pending hole gets range repair either way, under the same admission,
|
|
339
|
+
* priority and abort rules as a block request (class `unknown`, P0). Given,
|
|
340
|
+
* the scheduler FETCHes `repairFetchRange(x, K, anchor)` over it, and
|
|
341
|
+
* requires `repairEpochReference`. Absent, it walks the hole over
|
|
342
|
+
* `transport` one Group at a time from the hole's start, whose Group is a
|
|
343
|
+
* block's, each repair stating where the next block starts (BLO-52085),
|
|
344
|
+
* under the class of the hole's track (see the module note).
|
|
329
345
|
*/
|
|
330
346
|
rangeTransport?: RepairRangeFetchTransport;
|
|
331
347
|
/**
|
|
@@ -410,6 +426,12 @@ export interface RepairFetchHost {
|
|
|
410
426
|
holdBlockForRepair(sbn: number, packetId: number, catalogTrackName: string | undefined, untilAtMs: number): boolean;
|
|
411
427
|
/** The admitted FETCH ended without delivering: back to the multicast wait. */
|
|
412
428
|
releaseRepairHold(sbn: number, packetId: number, catalogTrackName?: string): void;
|
|
429
|
+
/** Run `fn` with `receivedAtMs` as the receipt time of what it feeds (optional). */
|
|
430
|
+
withReceiptTime?(receivedAtMs: number, fn: () => void): void;
|
|
431
|
+
/** The configured media kind of a packetId (optional; absent reads as video). */
|
|
432
|
+
trackKindFor?(packetId: number): TrackKind | undefined;
|
|
433
|
+
/** The stream's D-28 repair deadline: how long after a block's sources it asks for repair (optional). */
|
|
434
|
+
repairDeadlineMsForPacket?(packetId: number): number | undefined;
|
|
413
435
|
};
|
|
414
436
|
onRepairSubscribe(cb: RepairSubscribeCallback): void;
|
|
415
437
|
/**
|
|
@@ -423,8 +445,14 @@ export interface RepairFetchHost {
|
|
|
423
445
|
noteKeyframeBudgetGranted?(extensionMs: number, sbn: number, packetId: number, catalogTrackName?: string): void;
|
|
424
446
|
addRepairLifecycleObserver(observer: RepairLifecycleObserver): () => void;
|
|
425
447
|
addTrackResetObserver(observer: (packetId: number, catalogTrackName: string) => void): () => void;
|
|
426
|
-
/**
|
|
427
|
-
|
|
448
|
+
/**
|
|
449
|
+
* Register for lost SS_IDs in undelimited spans (required with
|
|
450
|
+
* `rangeTransport`). A host that offers it and `closeIsoHoles` keeps such a
|
|
451
|
+
* gap as a pending hole for the scheduler to repair. `onExpired` is told of
|
|
452
|
+
* a pending hole the stream ran past the locator's horizon; returning true,
|
|
453
|
+
* the scheduler closes it (`closeIsoHoles`), otherwise the host discards it.
|
|
454
|
+
*/
|
|
455
|
+
onUndelimitedLoss?(cb: (loss: UndelimitedIsoLoss) => void, onExpired?: (hole: ExpiredIsoHole) => boolean): void;
|
|
428
456
|
/** A hole's range repair ended, or none is sent: feed what was not stated. */
|
|
429
457
|
closeIsoHoles?(packetId: number, catalogTrackName: string | undefined, start: number, length: number): void;
|
|
430
458
|
clearRepairForBlock(sbn: number, packetId: number, catalogTrackName?: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repair-fetch.d.ts","sourceRoot":"","sources":["../src/repair-fetch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"repair-fetch.d.ts","sourceRoot":"","sources":["../src/repair-fetch.ts"],"names":[],"mappings":"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"}
|
package/dist/repair-fetch.js
CHANGED
|
@@ -1,13 +1,131 @@
|
|
|
1
1
|
// ../mmt-base/dist/mmtp.js
|
|
2
|
+
var MMTP_HEADER_SIZE = 12;
|
|
2
3
|
var MPU_HEADER_SIZE = 8;
|
|
3
4
|
var MPU_LENGTH_FIELD_SIZE = 2;
|
|
4
5
|
var MPU_HEADER_REMAINDER_SIZE = MPU_HEADER_SIZE - MPU_LENGTH_FIELD_SIZE;
|
|
6
|
+
var PACKET_TYPE_REPAIR = 3;
|
|
7
|
+
function parseMMTPHeader(buffer) {
|
|
8
|
+
if (buffer.length < MMTP_HEADER_SIZE) {
|
|
9
|
+
throw new Error(`MMTP packet too small: ${buffer.length} bytes`);
|
|
10
|
+
}
|
|
11
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
12
|
+
const version = buffer[0] >> 6 & 3;
|
|
13
|
+
if (version !== 0) {
|
|
14
|
+
throw new Error(`Unsupported MMTP version: ${version}`);
|
|
15
|
+
}
|
|
16
|
+
const fecType = buffer[0] >> 3 & 3;
|
|
17
|
+
const packetCounterFlag = (buffer[0] & 32) !== 0;
|
|
18
|
+
const extensionFlag = (buffer[0] & 2) !== 0;
|
|
19
|
+
const rapFlag = (buffer[0] & 1) === 1;
|
|
20
|
+
const packetType = buffer[1] & 63;
|
|
21
|
+
let offset = 2;
|
|
22
|
+
const packetId = view.getUint16(offset, false);
|
|
23
|
+
offset += 2;
|
|
24
|
+
const timestamp = BigInt(view.getUint32(offset, false));
|
|
25
|
+
offset += 4;
|
|
26
|
+
const sequenceNumber = view.getUint32(offset, false);
|
|
27
|
+
offset += 4;
|
|
28
|
+
let packetCounter;
|
|
29
|
+
if (packetCounterFlag) {
|
|
30
|
+
if (offset + 4 > buffer.length)
|
|
31
|
+
throw new Error("MMTP packet truncated in packet_counter");
|
|
32
|
+
packetCounter = view.getUint32(offset, false);
|
|
33
|
+
offset += 4;
|
|
34
|
+
}
|
|
35
|
+
let extension;
|
|
36
|
+
if (extensionFlag) {
|
|
37
|
+
if (offset + 4 > buffer.length)
|
|
38
|
+
throw new Error("MMTP packet truncated in header extension");
|
|
39
|
+
const type = view.getUint16(offset, false);
|
|
40
|
+
const length = view.getUint16(offset + 2, false);
|
|
41
|
+
offset += 4;
|
|
42
|
+
if (offset + length > buffer.length)
|
|
43
|
+
throw new Error("MMTP packet truncated in header extension value");
|
|
44
|
+
extension = { type, data: buffer.subarray(offset, offset + length) };
|
|
45
|
+
offset += length;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
version,
|
|
49
|
+
packetType,
|
|
50
|
+
packetId,
|
|
51
|
+
timestamp,
|
|
52
|
+
sequenceNumber,
|
|
53
|
+
payloadLength: buffer.length - offset,
|
|
54
|
+
fecType,
|
|
55
|
+
packetCounterFlag,
|
|
56
|
+
packetCounter,
|
|
57
|
+
extensionFlag,
|
|
58
|
+
extension,
|
|
59
|
+
headerLength: offset,
|
|
60
|
+
rapFlag
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
var REPAIR_FEC_PID_SIZE = 13;
|
|
64
|
+
function readRepairFecPayloadIdFields(mmtpPacket, parsedHeader) {
|
|
65
|
+
let header;
|
|
66
|
+
if (parsedHeader) {
|
|
67
|
+
header = parsedHeader;
|
|
68
|
+
} else {
|
|
69
|
+
try {
|
|
70
|
+
header = parseMMTPHeader(mmtpPacket);
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (header.packetType !== PACKET_TYPE_REPAIR || header.fecType !== 2)
|
|
76
|
+
return null;
|
|
77
|
+
const off = header.headerLength;
|
|
78
|
+
if (mmtpPacket.length < off + REPAIR_FEC_PID_SIZE)
|
|
79
|
+
return null;
|
|
80
|
+
const ssStart = (mmtpPacket[off] << 24 | mmtpPacket[off + 1] << 16 | mmtpPacket[off + 2] << 8 | mmtpPacket[off + 3]) >>> 0;
|
|
81
|
+
const rsbLength = mmtpPacket[off + 4] << 16 | mmtpPacket[off + 5] << 8 | mmtpPacket[off + 6];
|
|
82
|
+
const rsId = mmtpPacket[off + 7] << 16 | mmtpPacket[off + 8] << 8 | mmtpPacket[off + 9];
|
|
83
|
+
const ssbLength = mmtpPacket[off + 10] << 16 | mmtpPacket[off + 11] << 8 | mmtpPacket[off + 12];
|
|
84
|
+
return {
|
|
85
|
+
packetId: header.packetId,
|
|
86
|
+
ssStart,
|
|
87
|
+
rsbLength,
|
|
88
|
+
rsId,
|
|
89
|
+
ssbLength,
|
|
90
|
+
dataOffset: off + REPAIR_FEC_PID_SIZE
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function extractRepairFecPayloadId(mmtpPacket) {
|
|
94
|
+
const fields = readRepairFecPayloadIdFields(mmtpPacket);
|
|
95
|
+
if (!fields)
|
|
96
|
+
return null;
|
|
97
|
+
return {
|
|
98
|
+
ssStart: fields.ssStart,
|
|
99
|
+
rsbLength: fields.rsbLength,
|
|
100
|
+
rsId: fields.rsId,
|
|
101
|
+
ssbLength: fields.ssbLength
|
|
102
|
+
};
|
|
103
|
+
}
|
|
5
104
|
|
|
6
105
|
// ../mmt-base/dist/ntp-short.js
|
|
7
106
|
var NTP_SHORT_BITS = 32;
|
|
8
107
|
var NTP_SHORT_MODULUS = 2 ** NTP_SHORT_BITS;
|
|
9
108
|
var NTP_SHORT_HALF_RANGE = 2 ** (NTP_SHORT_BITS - 1);
|
|
10
109
|
|
|
110
|
+
// ../mmt-base/dist/serial-number.js
|
|
111
|
+
var SERIAL32_SPAN = 4294967296;
|
|
112
|
+
var SERIAL32_HALF = 2147483648;
|
|
113
|
+
function assertUint32(value, name) {
|
|
114
|
+
if (!Number.isInteger(value) || value < 0 || value >= SERIAL32_SPAN) {
|
|
115
|
+
throw new RangeError(`${name} must be a uint32 (got ${value})`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function serial32Add(s, n) {
|
|
119
|
+
assertUint32(s, "s");
|
|
120
|
+
if (!Number.isInteger(n) || n <= -SERIAL32_HALF || n >= SERIAL32_HALF) {
|
|
121
|
+
throw new RangeError(`serial addend must lie in (-2^31, 2^31) (got ${n})`);
|
|
122
|
+
}
|
|
123
|
+
return (s + n + SERIAL32_SPAN) % SERIAL32_SPAN;
|
|
124
|
+
}
|
|
125
|
+
function serial32Distance(from, to) {
|
|
126
|
+
return to - from >>> 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
11
129
|
// ../mmt-base/dist/fec-block-profile.js
|
|
12
130
|
var FEC_BLOCK_PROFILES = Object.freeze([
|
|
13
131
|
"iso-ssbg1-v1"
|
|
@@ -53,6 +171,7 @@ var REPAIR_PRIORITY_MIN = 192;
|
|
|
53
171
|
|
|
54
172
|
// src/repair-fetch.ts
|
|
55
173
|
var MOQT_PRIORITY_MAX = 255;
|
|
174
|
+
var WALK_LEAD_MS = 3;
|
|
56
175
|
var SOURCE_MEDIA_PRIORITY_MAX = REPAIR_PRIORITY_MIN - 1;
|
|
57
176
|
function isMoqtPriority(value) {
|
|
58
177
|
return Number.isSafeInteger(value) && value >= 0 && value <= MOQT_PRIORITY_MAX;
|
|
@@ -103,8 +222,17 @@ function wireRepairFetch(mc, opts) {
|
|
|
103
222
|
mc.noteRepairScheduling(type, entry.sbn, entry.packetId, entry.catalogTrackName);
|
|
104
223
|
};
|
|
105
224
|
const clearEntry = (entry) => {
|
|
106
|
-
|
|
107
|
-
|
|
225
|
+
const { range } = entry;
|
|
226
|
+
if (range) {
|
|
227
|
+
atReport(range, () => mc.closeIsoHoles(entry.packetId, entry.catalogTrackName, entry.sbn, range.holeLength));
|
|
228
|
+
} else {
|
|
229
|
+
clearRepair(entry.sbn, entry.packetId, entry.catalogTrackName);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
const atReport = (range, work) => {
|
|
233
|
+
const fec = mc.fecManager;
|
|
234
|
+
if (range.groups !== null || fec.withReceiptTime === void 0) work();
|
|
235
|
+
else fec.withReceiptTime(range.reportedAt, work);
|
|
108
236
|
};
|
|
109
237
|
const releaseHold = (entry) => {
|
|
110
238
|
if (entry.range) return;
|
|
@@ -171,21 +299,42 @@ function wireRepairFetch(mc, opts) {
|
|
|
171
299
|
const admit = (entry, now) => {
|
|
172
300
|
const budgetMs = entry.deadlineAt - now;
|
|
173
301
|
const rttMs = readRtt();
|
|
174
|
-
const reason =
|
|
302
|
+
const reason = refusal(entry, now, rttMs);
|
|
175
303
|
if (reason === null) return rttMs;
|
|
176
304
|
skip(entry, reason, rttMs, budgetMs);
|
|
177
305
|
return null;
|
|
178
306
|
};
|
|
307
|
+
const refusal = (entry, now, rttMs) => !entry.range && !groupCanComplete(entry.sbn, entry.packetId, entry.catalogTrackName) ? "group-cannot-complete" : rttMs === null ? "rtt-unmeasured" : rttMs < entry.deadlineAt - now ? null : "rtt-exceeds-budget";
|
|
179
308
|
const retire = (entry) => {
|
|
180
309
|
if (entries.get(entry.key) === entry) entries.delete(entry.key);
|
|
181
310
|
if (entry.expiry !== void 0) clearTimeout(entry.expiry);
|
|
182
311
|
};
|
|
183
|
-
const
|
|
312
|
+
const holdsBack = (entry, priority, videoWalks = true) => {
|
|
313
|
+
if (entry.priority >= priority) return false;
|
|
314
|
+
const { walk } = entry;
|
|
315
|
+
if (walk === void 0) return true;
|
|
316
|
+
if (entry.priority !== 0 || !videoWalks) return false;
|
|
317
|
+
return entry.running === null || walk.group !== null && !walk.group.controller.signal.aborted;
|
|
318
|
+
};
|
|
319
|
+
const outstandingBelow = (priority, videoWalks = true) => {
|
|
184
320
|
for (const entry of entries.values()) {
|
|
185
|
-
if (entry
|
|
321
|
+
if (holdsBack(entry, priority, videoWalks)) return true;
|
|
186
322
|
}
|
|
187
323
|
return false;
|
|
188
324
|
};
|
|
325
|
+
const yieldVideoWalks = (queued) => {
|
|
326
|
+
const now = performance.now();
|
|
327
|
+
const rttMs = readRtt();
|
|
328
|
+
const due = queued.some((entry) => entry.priority !== 0 && entry.walk === void 0 && !outstandingBelow(entry.priority, false) && refusal(entry, now, rttMs) === null);
|
|
329
|
+
if (!due) return;
|
|
330
|
+
for (const entry of entries.values()) {
|
|
331
|
+
const walk = entry.walk;
|
|
332
|
+
if (entry.priority !== 0 || walk === void 0 || walk.group === null) continue;
|
|
333
|
+
if (walk.group.controller.signal.aborted) continue;
|
|
334
|
+
walk.yielded = true;
|
|
335
|
+
walk.group.controller.abort();
|
|
336
|
+
}
|
|
337
|
+
};
|
|
189
338
|
const preemptBestEffort = () => {
|
|
190
339
|
for (const entry of entries.values()) {
|
|
191
340
|
if (entry.priority === 0 || !entry.running) continue;
|
|
@@ -214,7 +363,8 @@ function wireRepairFetch(mc, opts) {
|
|
|
214
363
|
}
|
|
215
364
|
const rttMs = admit(entry, now);
|
|
216
365
|
if (rttMs === null) return;
|
|
217
|
-
if (entry.priority === 0) preemptBestEffort();
|
|
366
|
+
if (entry.priority === 0 && entry.walk === void 0) preemptBestEffort();
|
|
367
|
+
if (entry.range === void 0) leaveWalkedGroup(entry);
|
|
218
368
|
if (counted) entry.attempts++;
|
|
219
369
|
mc.noteRepairFetchSent?.(entry.priority, entry.sbn, entry.packetId, entry.catalogTrackName, {
|
|
220
370
|
rttMs,
|
|
@@ -236,6 +386,14 @@ function wireRepairFetch(mc, opts) {
|
|
|
236
386
|
}
|
|
237
387
|
void execute(entry, run);
|
|
238
388
|
};
|
|
389
|
+
const leaveWalkedGroup = (block) => {
|
|
390
|
+
for (const entry of entries.values()) {
|
|
391
|
+
const group = entry.walk?.group;
|
|
392
|
+
if (group?.sbn === block.sbn && entry.packetId === block.packetId && entry.catalogTrackName === block.catalogTrackName) {
|
|
393
|
+
group.controller.abort();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
239
397
|
const dispatch = () => {
|
|
240
398
|
if (disposed) return;
|
|
241
399
|
const now = performance.now();
|
|
@@ -260,6 +418,7 @@ function wireRepairFetch(mc, opts) {
|
|
|
260
418
|
for (const entry of queued) {
|
|
261
419
|
if (entry.priority === 0) start(entry);
|
|
262
420
|
}
|
|
421
|
+
yieldVideoWalks(queued);
|
|
263
422
|
if (outstandingBelow(1)) return;
|
|
264
423
|
for (const entry of queued) {
|
|
265
424
|
if (entry.priority === 1) start(entry);
|
|
@@ -286,6 +445,16 @@ function wireRepairFetch(mc, opts) {
|
|
|
286
445
|
}
|
|
287
446
|
return counts.sources + counts.repairGroupLength >= counts.authoredLength;
|
|
288
447
|
};
|
|
448
|
+
const groupServed = (sbn, packetId, catalogTrackName) => {
|
|
449
|
+
if (mc.fecManager.blockSymbolCounts === void 0) return false;
|
|
450
|
+
const counts = symbolCounts(sbn, packetId, catalogTrackName);
|
|
451
|
+
if (counts === void 0 || counts.authoredLength === void 0) return true;
|
|
452
|
+
return counts.sources + counts.repairs >= counts.authoredLength || !groupCanComplete(sbn, packetId, catalogTrackName);
|
|
453
|
+
};
|
|
454
|
+
const statedEnd = (sbn, packetId, catalogTrackName) => {
|
|
455
|
+
const length = symbolCounts(sbn, packetId, catalogTrackName)?.authoredLength;
|
|
456
|
+
return length === void 0 ? void 0 : serial32Add(sbn, length);
|
|
457
|
+
};
|
|
289
458
|
const finish = (entry, run, fed, error) => {
|
|
290
459
|
if (run.stopped !== null || entry.running !== run || entries.get(entry.key) !== entry) {
|
|
291
460
|
return;
|
|
@@ -330,27 +499,81 @@ function wireRepairFetch(mc, opts) {
|
|
|
330
499
|
signal: run.controller.signal,
|
|
331
500
|
subscriberPriority: entry.subscriberPriority
|
|
332
501
|
};
|
|
502
|
+
const { range } = entry;
|
|
503
|
+
const feed = (packet) => {
|
|
504
|
+
if (entry.catalogTrackName === void 0) {
|
|
505
|
+
mc.processRepairFromMoQ(packet, entry.packetId);
|
|
506
|
+
} else {
|
|
507
|
+
mc.processRepairFromMoQ(packet, entry.packetId, entry.catalogTrackName);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
333
510
|
try {
|
|
334
|
-
const packets = entry.
|
|
511
|
+
const packets = range === void 0 ? opts.transport({ ...common, sbn: entry.sbn }) : entry.walk !== void 0 ? walkHole(entry, entry.walk, range, common) : opts.rangeTransport({
|
|
335
512
|
...common,
|
|
336
|
-
startGroup:
|
|
337
|
-
endGroup:
|
|
338
|
-
lostSsId:
|
|
339
|
-
})
|
|
513
|
+
startGroup: range.groups.startGroup,
|
|
514
|
+
endGroup: range.groups.endGroup,
|
|
515
|
+
lostSsId: range.lostSsId
|
|
516
|
+
});
|
|
340
517
|
for await (const packet of packets) {
|
|
341
518
|
if (run.stopped !== null || entry.running !== run) break;
|
|
342
519
|
fed++;
|
|
343
|
-
if (
|
|
344
|
-
|
|
345
|
-
} else {
|
|
346
|
-
mc.processRepairFromMoQ(packet, entry.packetId, entry.catalogTrackName);
|
|
347
|
-
}
|
|
520
|
+
if (range === void 0) feed(packet);
|
|
521
|
+
else atReport(range, () => feed(packet));
|
|
348
522
|
}
|
|
349
523
|
finish(entry, run, fed, void 0);
|
|
350
524
|
} catch (error) {
|
|
351
525
|
finish(entry, run, fed, error ?? new Error("repair transport rejected"));
|
|
352
526
|
}
|
|
353
527
|
};
|
|
528
|
+
async function* walkHole(entry, walk, hole, common) {
|
|
529
|
+
const lostAt = serial32Distance(entry.sbn, hole.lostSsId);
|
|
530
|
+
for (let first = true; !common.signal.aborted; first = false) {
|
|
531
|
+
if (!first && entry.priority !== 0 && outstandingBelow(1)) {
|
|
532
|
+
stop(entry, "preempted");
|
|
533
|
+
note("repair-preempted", entry);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
if (!first && entry.priority === 0) {
|
|
537
|
+
dispatch();
|
|
538
|
+
if (common.signal.aborted) return;
|
|
539
|
+
}
|
|
540
|
+
const sbn = walk.next;
|
|
541
|
+
let next;
|
|
542
|
+
if (entries.get(requestKey(sbn, entry.packetId, entry.catalogTrackName))?.running == null) {
|
|
543
|
+
const rsIds = /* @__PURE__ */ new Set();
|
|
544
|
+
const group = new AbortController();
|
|
545
|
+
const cancel = () => group.abort();
|
|
546
|
+
common.signal.addEventListener("abort", cancel, { once: true });
|
|
547
|
+
walk.group = { sbn, controller: group };
|
|
548
|
+
try {
|
|
549
|
+
for await (const packet of opts.transport({ ...common, sbn, signal: group.signal })) {
|
|
550
|
+
yield packet;
|
|
551
|
+
const id = extractRepairFecPayloadId(packet);
|
|
552
|
+
if (id === null || id.ssStart !== sbn || id.ssbLength === 0) continue;
|
|
553
|
+
next ??= serial32Add(sbn, id.ssbLength);
|
|
554
|
+
rsIds.add(id.rsId);
|
|
555
|
+
if (rsIds.size >= id.rsbLength || groupServed(sbn, entry.packetId, entry.catalogTrackName)) {
|
|
556
|
+
group.abort();
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
} catch (error) {
|
|
561
|
+
if (!group.signal.aborted || common.signal.aborted) throw error;
|
|
562
|
+
} finally {
|
|
563
|
+
common.signal.removeEventListener("abort", cancel);
|
|
564
|
+
walk.group = null;
|
|
565
|
+
}
|
|
566
|
+
if (walk.yielded) {
|
|
567
|
+
walk.yielded = false;
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
next ??= statedEnd(sbn, entry.packetId, entry.catalogTrackName);
|
|
572
|
+
if (next === void 0) return;
|
|
573
|
+
if (serial32Distance(entry.sbn, next) > lostAt) return;
|
|
574
|
+
walk.next = next;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
354
577
|
const removeResetObserver = mc.addTrackResetObserver((packetId, catalogTrackName) => {
|
|
355
578
|
for (const entry of [...entries.values()]) {
|
|
356
579
|
if (entry.packetId !== packetId || entry.catalogTrackName !== catalogTrackName) continue;
|
|
@@ -546,7 +769,37 @@ function wireRepairFetch(mc, opts) {
|
|
|
546
769
|
throw error;
|
|
547
770
|
}
|
|
548
771
|
};
|
|
549
|
-
|
|
772
|
+
const trackKind = (packetId) => {
|
|
773
|
+
try {
|
|
774
|
+
return mc.fecManager.trackKindFor?.(packetId);
|
|
775
|
+
} catch {
|
|
776
|
+
return void 0;
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
const walkDeadlineAt = (packetId, now, deadlineAt) => {
|
|
780
|
+
let repairDeadlineMs;
|
|
781
|
+
try {
|
|
782
|
+
repairDeadlineMs = mc.fecManager.repairDeadlineMsForPacket?.(packetId);
|
|
783
|
+
} catch {
|
|
784
|
+
repairDeadlineMs = void 0;
|
|
785
|
+
}
|
|
786
|
+
if (repairDeadlineMs === void 0 || !Number.isFinite(repairDeadlineMs)) return deadlineAt;
|
|
787
|
+
return Math.min(deadlineAt, now + repairDeadlineMs - WALK_LEAD_MS);
|
|
788
|
+
};
|
|
789
|
+
const onHoleExpired = (hole) => {
|
|
790
|
+
if (disposed) return false;
|
|
791
|
+
const entry = [...entries.values()].find((candidate) => candidate.walk !== void 0 && candidate.packetId === hole.packetId && candidate.catalogTrackName === hole.catalogTrackName && serial32Distance(candidate.sbn, hole.holeStart) < candidate.range.holeLength);
|
|
792
|
+
if (entry === void 0) return false;
|
|
793
|
+
queueMicrotask(() => {
|
|
794
|
+
if (entries.get(entry.key) !== entry) return;
|
|
795
|
+
retire(entry);
|
|
796
|
+
stop(entry, "expired");
|
|
797
|
+
clearEntry(entry);
|
|
798
|
+
dispatch();
|
|
799
|
+
});
|
|
800
|
+
return true;
|
|
801
|
+
};
|
|
802
|
+
if (mc.onUndelimitedLoss !== void 0 && mc.closeIsoHoles !== void 0) {
|
|
550
803
|
mc.onUndelimitedLoss((loss) => {
|
|
551
804
|
const { packetId, catalogTrackName, holeStart, holeLength } = loss;
|
|
552
805
|
const close = () => mc.closeIsoHoles(packetId, catalogTrackName, holeStart, holeLength);
|
|
@@ -554,9 +807,11 @@ function wireRepairFetch(mc, opts) {
|
|
|
554
807
|
const blockProfile = blockProfileOf(packetId);
|
|
555
808
|
const target = opts.resolveTarget(packetId, catalogTrackName);
|
|
556
809
|
if (!target) return close();
|
|
557
|
-
const
|
|
558
|
-
const
|
|
559
|
-
|
|
810
|
+
const walked = opts.rangeTransport === void 0;
|
|
811
|
+
const holeClass = walked && trackKind(packetId) === "audio" ? "audio" : "unknown";
|
|
812
|
+
const priority = repairPriorityForClass(holeClass);
|
|
813
|
+
const groups = walked ? null : rangeFor(loss, target.repairTrack);
|
|
814
|
+
if (!walked && groups === null) {
|
|
560
815
|
close();
|
|
561
816
|
mc.noteRepairSkipped("range-no-anchor", { rttMs: readRtt(), budgetMs: 0, priority }, holeStart, packetId, catalogTrackName);
|
|
562
817
|
return;
|
|
@@ -567,8 +822,10 @@ function wireRepairFetch(mc, opts) {
|
|
|
567
822
|
packetId,
|
|
568
823
|
...catalogTrackName === void 0 ? {} : { catalogTrackName }
|
|
569
824
|
};
|
|
570
|
-
const wire = wirePriority(identity,
|
|
571
|
-
|
|
825
|
+
const wire = wirePriority(identity, holeClass);
|
|
826
|
+
if (wire === null) return close();
|
|
827
|
+
const now = performance.now();
|
|
828
|
+
const deadline = presentationDeadlineAt(holeStart, packetId, catalogTrackName, now, holeClass);
|
|
572
829
|
if (deadline === null) {
|
|
573
830
|
close();
|
|
574
831
|
mc.noteRepairSkipped(
|
|
@@ -580,6 +837,7 @@ function wireRepairFetch(mc, opts) {
|
|
|
580
837
|
);
|
|
581
838
|
return;
|
|
582
839
|
}
|
|
840
|
+
const deadlineAt = walked ? walkDeadlineAt(packetId, now, deadline.deadlineAt) : deadline.deadlineAt;
|
|
583
841
|
const entry = {
|
|
584
842
|
key: JSON.stringify(["range", packetId, catalogTrackName ?? null, holeStart]),
|
|
585
843
|
...identity,
|
|
@@ -587,15 +845,16 @@ function wireRepairFetch(mc, opts) {
|
|
|
587
845
|
blockProfile,
|
|
588
846
|
priority,
|
|
589
847
|
subscriberPriority: wire.subscriberPriority,
|
|
590
|
-
deadlineAt
|
|
591
|
-
playoutDeadlineAt:
|
|
848
|
+
deadlineAt,
|
|
849
|
+
playoutDeadlineAt: deadlineAt - deadline.extensionMs,
|
|
592
850
|
anchorAt: deadline.anchorAt,
|
|
593
851
|
delayMs: deadline.delayMs,
|
|
594
852
|
bound: deadline.bound,
|
|
595
853
|
order: enqueueOrder++,
|
|
596
854
|
attempts: 0,
|
|
597
855
|
running: null,
|
|
598
|
-
range: {
|
|
856
|
+
range: { lostSsId: loss.lostSsId, holeLength, groups, reportedAt: now },
|
|
857
|
+
...walked ? { walk: { next: holeStart, group: null, yielded: false } } : {}
|
|
599
858
|
};
|
|
600
859
|
const previous = entries.get(entry.key);
|
|
601
860
|
if (previous) {
|
|
@@ -605,7 +864,7 @@ function wireRepairFetch(mc, opts) {
|
|
|
605
864
|
entries.set(entry.key, entry);
|
|
606
865
|
entry.expiry = setTimeout(dispatch, Math.max(0, entry.deadlineAt - performance.now()) + 1);
|
|
607
866
|
dispatch();
|
|
608
|
-
});
|
|
867
|
+
}, onHoleExpired);
|
|
609
868
|
}
|
|
610
869
|
const removeRapObserver = mc.addRapCompleteObserver?.((packetId) => {
|
|
611
870
|
queueMicrotask(() => {
|