@blockcast/mmt-container 0.1.0-main.cde7600fad6a → 0.1.0-main.ce3c8aeb7f68
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 +276 -178
- package/dist/browser-runtime.js.map +3 -3
- package/dist/carp-catalog.js.map +1 -1
- package/dist/catalog-fec-params.js.map +1 -1
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +35 -2
- package/dist/fec-manager.js.map +2 -2
- package/dist/fec-worker-setup.js +22 -1
- package/dist/fec-worker-setup.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +2 -2
- package/dist/mfu-reassembler.js +17 -11
- package/dist/mfu-reassembler.js.map +2 -2
- package/dist/mmtp-container-parser.d.ts +28 -0
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +75 -49
- package/dist/mmtp-container-parser.js.map +3 -3
- package/dist/mmtp-container-parser.no-modules.js +85 -59
- package/dist/mmtp-container-parser.no-modules.js.map +3 -3
- package/dist/mmtp-decode-pipeline.js +75 -49
- package/dist/mmtp-decode-pipeline.js.map +3 -3
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +218 -159
- package/dist/mmtp-router.js.map +3 -3
- package/dist/multicast-input.js.map +1 -1
- package/dist/multicast-manager.js +276 -165
- package/dist/multicast-manager.js.map +3 -3
- package/dist/multicast-transport.js +17 -54
- package/dist/multicast-transport.js.map +2 -2
- package/dist/multicast-unwrap.js +53 -30
- package/dist/multicast-unwrap.js.map +2 -2
- package/dist/no-modules.js +75 -49
- package/dist/no-modules.js.map +3 -3
- package/dist/signaling.js.map +2 -2
- package/dist/timestamp-codec.js +17 -11
- package/dist/timestamp-codec.js.map +2 -2
- package/dist/wasm-mfu-reassembler.js.map +1 -1
- package/dist/wasm-mmtp-container-parser.js +75 -49
- package/dist/wasm-mmtp-container-parser.js.map +3 -3
- package/node_modules/@blockcast/fec-worker/README.md +5 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts +6 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts.map +1 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js +25 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js.map +1 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +10 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.js +6 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.js.map +2 -2
- package/node_modules/@blockcast/fec-worker/src/fec-worker-client.ts +29 -1
- package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +8 -1
- package/node_modules/@blockcast/fec-worker/src/fec-worker.ts +7 -1
- package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +42 -0
- package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-base/dist/mmtp.js +132 -37
- package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -1
- package/node_modules/@blockcast/mmt-base/src/mmtp.ts +146 -37
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +42 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js +132 -37
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -1
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/mmtp.ts +146 -37
- package/package.json +7 -7
- package/src/fec-manager.ts +35 -2
- package/src/index.ts +1 -0
- package/src/mmtp-container-parser.ts +78 -21
- package/src/mmtp-router.ts +147 -121
- package/src/multicast-transport.ts +7 -7
package/dist/browser-runtime.js
CHANGED
|
@@ -63,6 +63,11 @@ var init_fec_worker_client = __esm({
|
|
|
63
63
|
#flushQueued = false;
|
|
64
64
|
// Batching starts only once the Worker announced it accepts feedSymbols.
|
|
65
65
|
#batchSymbols = false;
|
|
66
|
+
// The Worker posts blockUpdate events only to a client that subscribed,
|
|
67
|
+
// which this client does once a callback is registered and the Worker
|
|
68
|
+
// announced the command (BLO-36599).
|
|
69
|
+
#blockUpdatesAnnounced = false;
|
|
70
|
+
#blockUpdatesSubscribed = false;
|
|
66
71
|
/**
|
|
67
72
|
* Create a FecWorkerClient.
|
|
68
73
|
* @param workerOrUrl - Either a Worker instance (for testing) or a URL to create one
|
|
@@ -225,9 +230,21 @@ var init_fec_worker_client = __esm({
|
|
|
225
230
|
onSnapshot(cb) {
|
|
226
231
|
this.#onSnapshot = cb;
|
|
227
232
|
}
|
|
228
|
-
/**
|
|
233
|
+
/**
|
|
234
|
+
* Register callback for individual block state changes. The Worker posts
|
|
235
|
+
* them only once asked, so registering subscribes (after the Worker
|
|
236
|
+
* announces `subscribeBlockUpdates`). An older Worker that does not
|
|
237
|
+
* announce it posts them unasked.
|
|
238
|
+
*/
|
|
229
239
|
onBlockUpdate(cb) {
|
|
230
240
|
this.#onBlockUpdate = cb;
|
|
241
|
+
this.#subscribeBlockUpdates();
|
|
242
|
+
}
|
|
243
|
+
#subscribeBlockUpdates() {
|
|
244
|
+
if (this.#disposed || this.#blockUpdatesSubscribed || !this.#blockUpdatesAnnounced || !this.#onBlockUpdate)
|
|
245
|
+
return;
|
|
246
|
+
this.#blockUpdatesSubscribed = true;
|
|
247
|
+
this.#worker.postMessage({ type: "subscribeBlockUpdates" });
|
|
231
248
|
}
|
|
232
249
|
/** Register callback for green-fill frames. */
|
|
233
250
|
onGreenFill(cb) {
|
|
@@ -270,6 +287,10 @@ var init_fec_worker_client = __esm({
|
|
|
270
287
|
if (Array.isArray(event.commands) && event.commands.includes("feedSymbols")) {
|
|
271
288
|
this.#batchSymbols = true;
|
|
272
289
|
}
|
|
290
|
+
if (Array.isArray(event.commands) && event.commands.includes("subscribeBlockUpdates")) {
|
|
291
|
+
this.#blockUpdatesAnnounced = true;
|
|
292
|
+
this.#subscribeBlockUpdates();
|
|
293
|
+
}
|
|
273
294
|
return;
|
|
274
295
|
}
|
|
275
296
|
if (event.type === "resetComplete") {
|
|
@@ -616,6 +637,27 @@ function parseMMTPHeader(buffer) {
|
|
|
616
637
|
rapFlag
|
|
617
638
|
};
|
|
618
639
|
}
|
|
640
|
+
function readMMTPPacketId(buffer) {
|
|
641
|
+
if (buffer.length < MMTP_HEADER_SIZE2)
|
|
642
|
+
return null;
|
|
643
|
+
const flags = buffer[0];
|
|
644
|
+
if ((flags >> 6 & 3) !== 0)
|
|
645
|
+
return null;
|
|
646
|
+
let offset = MMTP_HEADER_SIZE2;
|
|
647
|
+
if ((flags & 32) !== 0) {
|
|
648
|
+
if (offset + 4 > buffer.length)
|
|
649
|
+
return null;
|
|
650
|
+
offset += 4;
|
|
651
|
+
}
|
|
652
|
+
if ((flags & 2) !== 0) {
|
|
653
|
+
if (offset + 4 > buffer.length)
|
|
654
|
+
return null;
|
|
655
|
+
const length = buffer[offset + 2] << 8 | buffer[offset + 3];
|
|
656
|
+
if (offset + 4 + length > buffer.length)
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
return buffer[2] << 8 | buffer[3];
|
|
660
|
+
}
|
|
619
661
|
function unwrapMMTP(buffer) {
|
|
620
662
|
const header = parseMMTPHeader(buffer);
|
|
621
663
|
const payload = buffer.subarray(header.headerLength);
|
|
@@ -729,7 +771,7 @@ function extractNALUnit(mmtpPacket) {
|
|
|
729
771
|
throw new Error("Malformed MMTP MPU payload");
|
|
730
772
|
return extraction.data;
|
|
731
773
|
}
|
|
732
|
-
function planMfuExtraction(mmtpPacket, options) {
|
|
774
|
+
function planMfuExtraction(mmtpPacket, options, parsedHeader) {
|
|
733
775
|
if (mmtpPacket.length < MMTP_HEADER_SIZE2 + MPU_HEADER_SIZE2) {
|
|
734
776
|
return {
|
|
735
777
|
rejection: {
|
|
@@ -739,15 +781,19 @@ function planMfuExtraction(mmtpPacket, options) {
|
|
|
739
781
|
};
|
|
740
782
|
}
|
|
741
783
|
let header;
|
|
742
|
-
|
|
743
|
-
header =
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
784
|
+
if (parsedHeader) {
|
|
785
|
+
header = parsedHeader;
|
|
786
|
+
} else {
|
|
787
|
+
try {
|
|
788
|
+
header = parseMMTPHeader(mmtpPacket);
|
|
789
|
+
} catch (error) {
|
|
790
|
+
return {
|
|
791
|
+
rejection: {
|
|
792
|
+
gate: "mmtp-header-unparseable",
|
|
793
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
}
|
|
751
797
|
}
|
|
752
798
|
if (header.packetType !== PACKET_TYPE_MPU2) {
|
|
753
799
|
return {
|
|
@@ -800,7 +846,12 @@ function planMfuExtraction(mmtpPacket, options) {
|
|
|
800
846
|
return { plan: { header, payload, mpu, fragmentType, layout, trailerLayout } };
|
|
801
847
|
}
|
|
802
848
|
function extractMFUPayload(mmtpPacket, options) {
|
|
803
|
-
|
|
849
|
+
return extractPlannedMfu(mmtpPacket, planMfuExtraction(mmtpPacket, options));
|
|
850
|
+
}
|
|
851
|
+
function extractMFUPayloadWithHeader(mmtpPacket, header, options) {
|
|
852
|
+
return extractPlannedMfu(mmtpPacket, planMfuExtraction(mmtpPacket, options, header));
|
|
853
|
+
}
|
|
854
|
+
function extractPlannedMfu(mmtpPacket, result) {
|
|
804
855
|
if ("rejection" in result)
|
|
805
856
|
return null;
|
|
806
857
|
const { header, payload, mpu, fragmentType, layout, trailerLayout } = result.plan;
|
|
@@ -825,51 +876,59 @@ function isFecRepairPacket(mmtpPacket) {
|
|
|
825
876
|
const fecType = mmtpPacket[0] >> 3 & 3;
|
|
826
877
|
return fecType >= 2;
|
|
827
878
|
}
|
|
828
|
-
function extractFecPayloadId(mmtpPacket) {
|
|
829
|
-
if (!hasSourceFecPayloadId(mmtpPacket))
|
|
830
|
-
return null;
|
|
831
|
-
const off = mmtpPacket.length - SOURCE_FEC_PAYLOAD_ID_SIZE;
|
|
832
|
-
const view2 = new DataView(mmtpPacket.buffer, mmtpPacket.byteOffset + off, SOURCE_FEC_PAYLOAD_ID_SIZE);
|
|
833
|
-
return { ssId: view2.getUint32(0, false) };
|
|
834
|
-
}
|
|
835
879
|
function hasSourceFecPayloadId(mmtpPacket) {
|
|
880
|
+
const header = parseHeaderForSourceFecId(mmtpPacket);
|
|
881
|
+
return header !== null && sourceFecPayloadIdOf(mmtpPacket, header) !== null;
|
|
882
|
+
}
|
|
883
|
+
function parseHeaderForSourceFecId(mmtpPacket) {
|
|
836
884
|
if (mmtpPacket.length < MMTP_HEADER_SIZE2 + MPU_HEADER_SIZE2)
|
|
837
|
-
return
|
|
838
|
-
let header;
|
|
885
|
+
return null;
|
|
839
886
|
try {
|
|
840
|
-
|
|
887
|
+
return parseMMTPHeader(mmtpPacket);
|
|
841
888
|
} catch {
|
|
842
|
-
return
|
|
889
|
+
return null;
|
|
843
890
|
}
|
|
891
|
+
}
|
|
892
|
+
function sourceFecPayloadIdOf(mmtpPacket, header) {
|
|
893
|
+
if (mmtpPacket.length < MMTP_HEADER_SIZE2 + MPU_HEADER_SIZE2)
|
|
894
|
+
return null;
|
|
844
895
|
if (header.packetType !== PACKET_TYPE_MPU2)
|
|
845
|
-
return
|
|
896
|
+
return null;
|
|
846
897
|
const payload = mmtpPacket.subarray(header.headerLength);
|
|
847
898
|
if (payload.length < MPU_HEADER_SIZE2)
|
|
848
|
-
return
|
|
849
|
-
const
|
|
850
|
-
if (
|
|
851
|
-
return
|
|
852
|
-
const declaredEnd = MPU_LENGTH_FIELD_SIZE2 +
|
|
853
|
-
|
|
899
|
+
return null;
|
|
900
|
+
const payloadLength = payload[0] << 8 | payload[1];
|
|
901
|
+
if (payloadLength < MPU_HEADER_REMAINDER_SIZE2)
|
|
902
|
+
return null;
|
|
903
|
+
const declaredEnd = MPU_LENGTH_FIELD_SIZE2 + payloadLength;
|
|
904
|
+
if (!resolveDeclaredTrailers(payload, declaredEnd, header.fecType)?.hasFecId)
|
|
905
|
+
return null;
|
|
906
|
+
const off = mmtpPacket.length - SOURCE_FEC_PAYLOAD_ID_SIZE;
|
|
907
|
+
return {
|
|
908
|
+
ssId: (mmtpPacket[off] << 24 | mmtpPacket[off + 1] << 16 | mmtpPacket[off + 2] << 8 | mmtpPacket[off + 3]) >>> 0
|
|
909
|
+
};
|
|
854
910
|
}
|
|
855
911
|
var MMTP_EXT_TYPE_ALTA_AUTH2 = MMTP_EXT_TYPE_ALTA_AUTH;
|
|
856
912
|
var MMTP_EXT_TRAILER_HEADER_SIZE2 = MMTP_EXT_TRAILER_HEADER_SIZE;
|
|
857
913
|
var extractAltaTrailer2 = extractAltaTrailer;
|
|
858
914
|
var REPAIR_FEC_PID_SIZE = 13;
|
|
859
|
-
function readRepairFecPayloadIdFields(mmtpPacket) {
|
|
915
|
+
function readRepairFecPayloadIdFields(mmtpPacket, parsedHeader) {
|
|
860
916
|
let header;
|
|
861
|
-
|
|
862
|
-
header =
|
|
863
|
-
}
|
|
864
|
-
|
|
917
|
+
if (parsedHeader) {
|
|
918
|
+
header = parsedHeader;
|
|
919
|
+
} else {
|
|
920
|
+
try {
|
|
921
|
+
header = parseMMTPHeader(mmtpPacket);
|
|
922
|
+
} catch {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
865
925
|
}
|
|
866
926
|
if (header.packetType !== PACKET_TYPE_REPAIR || header.fecType !== 2)
|
|
867
927
|
return null;
|
|
868
928
|
const off = header.headerLength;
|
|
869
929
|
if (mmtpPacket.length < off + REPAIR_FEC_PID_SIZE)
|
|
870
930
|
return null;
|
|
871
|
-
const
|
|
872
|
-
const ssStart = view2.getUint32(0, false);
|
|
931
|
+
const ssStart = (mmtpPacket[off] << 24 | mmtpPacket[off + 1] << 16 | mmtpPacket[off + 2] << 8 | mmtpPacket[off + 3]) >>> 0;
|
|
873
932
|
const rsbLength = mmtpPacket[off + 4] << 16 | mmtpPacket[off + 5] << 8 | mmtpPacket[off + 6];
|
|
874
933
|
const rsId = mmtpPacket[off + 7] << 16 | mmtpPacket[off + 8] << 8 | mmtpPacket[off + 9];
|
|
875
934
|
const ssbLength = mmtpPacket[off + 10] << 16 | mmtpPacket[off + 11] << 8 | mmtpPacket[off + 12];
|
|
@@ -883,7 +942,12 @@ function readRepairFecPayloadIdFields(mmtpPacket) {
|
|
|
883
942
|
};
|
|
884
943
|
}
|
|
885
944
|
function parseMoqRepairFrame(frame) {
|
|
886
|
-
|
|
945
|
+
return moqRepairFrameFrom(frame, readRepairFecPayloadIdFields(frame));
|
|
946
|
+
}
|
|
947
|
+
function parseMoqRepairFrameWithHeader(frame, header) {
|
|
948
|
+
return moqRepairFrameFrom(frame, readRepairFecPayloadIdFields(frame, header));
|
|
949
|
+
}
|
|
950
|
+
function moqRepairFrameFrom(frame, repairId) {
|
|
887
951
|
if (!repairId)
|
|
888
952
|
return null;
|
|
889
953
|
const symbolData = frame.subarray(repairId.dataOffset);
|
|
@@ -8980,17 +9044,6 @@ function fecBlockBudgetMs(interleaveDepthMs, reorderToleranceMs) {
|
|
|
8980
9044
|
}
|
|
8981
9045
|
return Math.ceil(interleaveDepthMs + reorderToleranceMs);
|
|
8982
9046
|
}
|
|
8983
|
-
function parseRepairPacket(packet) {
|
|
8984
|
-
const parsed = parseMoqRepairFrame(packet);
|
|
8985
|
-
if (!parsed)
|
|
8986
|
-
return null;
|
|
8987
|
-
return {
|
|
8988
|
-
ssStart: parsed.ssStart,
|
|
8989
|
-
ssbLength: parsed.ssbLength,
|
|
8990
|
-
rsId: parsed.rsId,
|
|
8991
|
-
repairData: parsed.symbolData
|
|
8992
|
-
};
|
|
8993
|
-
}
|
|
8994
9047
|
|
|
8995
9048
|
// ../fec/dist/fec-block-mapper.js
|
|
8996
9049
|
var FecBlockMapper = class {
|
|
@@ -9836,6 +9889,17 @@ var FECManager = class {
|
|
|
9836
9889
|
// Stable per-name encodings for stream and block keys, bounded by the
|
|
9837
9890
|
// catalog's track names; #blockKey is built several times per packet.
|
|
9838
9891
|
this.#encodedTrackNames = /* @__PURE__ */ new Map();
|
|
9892
|
+
// The last block and stream key built. One packet asks for the same block's
|
|
9893
|
+
// key from every FECManager entry point it passes through (~6 per source
|
|
9894
|
+
// symbol), so each key is built once per packet rather than once per call
|
|
9895
|
+
// (BLO-36599). Both keys are pure functions of their arguments.
|
|
9896
|
+
this.#lastBlockKeySbn = -1;
|
|
9897
|
+
this.#lastBlockKeyPacketId = -1;
|
|
9898
|
+
this.#lastBlockKeyTrackName = void 0;
|
|
9899
|
+
this.#lastBlockKey = "";
|
|
9900
|
+
this.#lastStreamKeyPacketId = -1;
|
|
9901
|
+
this.#lastStreamKeyTrackName = void 0;
|
|
9902
|
+
this.#lastStreamKey = "";
|
|
9839
9903
|
this.#seenSymbols = /* @__PURE__ */ new Set();
|
|
9840
9904
|
this.#blockPathCounts = /* @__PURE__ */ new Map();
|
|
9841
9905
|
// Exact catalog identity observed on accepted symbols for each FEC block.
|
|
@@ -9961,6 +10025,13 @@ var FECManager = class {
|
|
|
9961
10025
|
#terminalQueues;
|
|
9962
10026
|
#blockKeysBySbn;
|
|
9963
10027
|
#encodedTrackNames;
|
|
10028
|
+
#lastBlockKeySbn;
|
|
10029
|
+
#lastBlockKeyPacketId;
|
|
10030
|
+
#lastBlockKeyTrackName;
|
|
10031
|
+
#lastBlockKey;
|
|
10032
|
+
#lastStreamKeyPacketId;
|
|
10033
|
+
#lastStreamKeyTrackName;
|
|
10034
|
+
#lastStreamKey;
|
|
9964
10035
|
#seenSymbols;
|
|
9965
10036
|
#blockPathCounts;
|
|
9966
10037
|
#blockCatalogTrackNames;
|
|
@@ -9990,7 +10061,14 @@ var FECManager = class {
|
|
|
9990
10061
|
return encoded;
|
|
9991
10062
|
}
|
|
9992
10063
|
#streamKey(packetId, catalogTrackName) {
|
|
9993
|
-
|
|
10064
|
+
if (packetId === this.#lastStreamKeyPacketId && catalogTrackName === this.#lastStreamKeyTrackName) {
|
|
10065
|
+
return this.#lastStreamKey;
|
|
10066
|
+
}
|
|
10067
|
+
const key = catalogTrackName === void 0 ? `${packetId}` : `${packetId}:${this.#encodeTrackName(catalogTrackName)}`;
|
|
10068
|
+
this.#lastStreamKeyPacketId = packetId;
|
|
10069
|
+
this.#lastStreamKeyTrackName = catalogTrackName;
|
|
10070
|
+
this.#lastStreamKey = key;
|
|
10071
|
+
return key;
|
|
9994
10072
|
}
|
|
9995
10073
|
#belongsToPacket(key, packetId) {
|
|
9996
10074
|
return Number(key.split(":", 1)[0]) === packetId;
|
|
@@ -10015,8 +10093,16 @@ var FECManager = class {
|
|
|
10015
10093
|
};
|
|
10016
10094
|
}
|
|
10017
10095
|
#blockKey(sbn, packetId, catalogTrackName) {
|
|
10096
|
+
if (sbn === this.#lastBlockKeySbn && packetId === this.#lastBlockKeyPacketId && catalogTrackName === this.#lastBlockKeyTrackName) {
|
|
10097
|
+
return this.#lastBlockKey;
|
|
10098
|
+
}
|
|
10018
10099
|
const base = `${packetId}:${sbn}`;
|
|
10019
|
-
|
|
10100
|
+
const key = catalogTrackName === void 0 ? base : `${base}:${this.#encodeTrackName(catalogTrackName)}`;
|
|
10101
|
+
this.#lastBlockKeySbn = sbn;
|
|
10102
|
+
this.#lastBlockKeyPacketId = packetId;
|
|
10103
|
+
this.#lastBlockKeyTrackName = catalogTrackName;
|
|
10104
|
+
this.#lastBlockKey = key;
|
|
10105
|
+
return key;
|
|
10020
10106
|
}
|
|
10021
10107
|
/** Record that `key` (block `sbn` on `packetId`) is held by a lookup set. */
|
|
10022
10108
|
#indexBlockKey(key, sbn, packetId) {
|
|
@@ -12646,20 +12732,35 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12646
12732
|
* Returns null for malformed packets.
|
|
12647
12733
|
*/
|
|
12648
12734
|
parseHeader(packet, options) {
|
|
12735
|
+
return this.parsePacket(packet, options)?.info ?? null;
|
|
12736
|
+
}
|
|
12737
|
+
/**
|
|
12738
|
+
* parseHeader() that also keeps the parsed MMTP header, so a caller that
|
|
12739
|
+
* goes on to feedParsed() the same packet parses its header exactly once.
|
|
12740
|
+
* The MMTP header is parsed once here and the Source FEC Payload ID is read
|
|
12741
|
+
* from it; parseHeader() used to parse the header three times for an FEC
|
|
12742
|
+
* source packet, and feed() repeated all of it (BLO-36599).
|
|
12743
|
+
*/
|
|
12744
|
+
parsePacket(packet, options) {
|
|
12649
12745
|
try {
|
|
12650
12746
|
const header = parseMMTPHeader(packet);
|
|
12651
12747
|
const isRepair = header.packetType === PACKET_TYPE_REPAIR;
|
|
12652
|
-
const
|
|
12748
|
+
const skipFecPayloadId = options?.skipFecPayloadId === true;
|
|
12749
|
+
const fecPayloadId = !skipFecPayloadId && !isRepair ? sourceFecPayloadIdOf(packet, header) : null;
|
|
12653
12750
|
return {
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12751
|
+
info: {
|
|
12752
|
+
packetId: header.packetId,
|
|
12753
|
+
packetType: header.packetType,
|
|
12754
|
+
timestamp: header.timestamp,
|
|
12755
|
+
timestampUs: mmtpTimestampToMicros(header.timestamp),
|
|
12756
|
+
sequenceNumber: header.sequenceNumber,
|
|
12757
|
+
rapFlag: header.rapFlag,
|
|
12758
|
+
fecType: header.fecType,
|
|
12759
|
+
fecPayloadId,
|
|
12760
|
+
isRepair
|
|
12761
|
+
},
|
|
12762
|
+
header,
|
|
12763
|
+
skipFecPayloadId
|
|
12663
12764
|
};
|
|
12664
12765
|
} catch {
|
|
12665
12766
|
return null;
|
|
@@ -12667,10 +12768,22 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12667
12768
|
}
|
|
12668
12769
|
/** Feed a complete MMTP packet. For two-phase use, call parseHeader() first. */
|
|
12669
12770
|
feed(packet, options) {
|
|
12771
|
+
return this.#feedCounted(packet, options, void 0);
|
|
12772
|
+
}
|
|
12773
|
+
/**
|
|
12774
|
+
* feed() for a packet this caller already ran through parsePacket(): the
|
|
12775
|
+
* header parse is reused instead of repeated. `parsed` must come from
|
|
12776
|
+
* parsePacket() of this same, unmodified packet. If it was resolved under a
|
|
12777
|
+
* different skipFecPayloadId option, the packet is parsed again.
|
|
12778
|
+
*/
|
|
12779
|
+
feedParsed(packet, parsed, options) {
|
|
12780
|
+
return this.#feedCounted(packet, options, parsed);
|
|
12781
|
+
}
|
|
12782
|
+
#feedCounted(packet, options, parsed) {
|
|
12670
12783
|
this.#fedObjects += 1;
|
|
12671
12784
|
let record;
|
|
12672
12785
|
try {
|
|
12673
|
-
record = this.#feed(packet, options);
|
|
12786
|
+
record = this.#feed(packet, options, parsed);
|
|
12674
12787
|
} catch (error) {
|
|
12675
12788
|
this.#countOutcome("drop:threw");
|
|
12676
12789
|
throw error;
|
|
@@ -12678,11 +12791,12 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12678
12791
|
if (record) this.#countOutcome(record.kind);
|
|
12679
12792
|
return record;
|
|
12680
12793
|
}
|
|
12681
|
-
#feed(packet, options) {
|
|
12794
|
+
#feed(packet, options, preParsed) {
|
|
12682
12795
|
if (this.#disposed) return this.#drop("disposed");
|
|
12683
12796
|
this.cleanupTimeouts();
|
|
12684
|
-
const
|
|
12685
|
-
if (!
|
|
12797
|
+
const parsed = preParsed !== void 0 && preParsed.skipFecPayloadId === (options?.skipFecPayloadId === true) ? preParsed : this.parsePacket(packet, options);
|
|
12798
|
+
if (!parsed) return this.#drop("header-parse-failed");
|
|
12799
|
+
const info = parsed.info;
|
|
12686
12800
|
if (info.packetType !== PACKET_TYPE_MPU2) {
|
|
12687
12801
|
return {
|
|
12688
12802
|
kind: info.isRepair ? "repair" : "non-media",
|
|
@@ -12699,7 +12813,7 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12699
12813
|
} catch {
|
|
12700
12814
|
}
|
|
12701
12815
|
}
|
|
12702
|
-
const extraction =
|
|
12816
|
+
const extraction = extractMFUPayloadWithHeader(packet, parsed.header, {
|
|
12703
12817
|
skipFecId: options?.skipFecPayloadId
|
|
12704
12818
|
});
|
|
12705
12819
|
if (!extraction) return this.#drop("mfu-extract-failed");
|
|
@@ -13393,6 +13507,17 @@ function ingressHasPacketId(ingress, packetId) {
|
|
|
13393
13507
|
if (packetId === MMTP_SIGNALING_PACKET_ID) return false;
|
|
13394
13508
|
return ingress === void 0 || ingressEntry(ingress, packetId) !== void 0;
|
|
13395
13509
|
}
|
|
13510
|
+
var PACKET_LEDGER_HIGH_WATER = 4e3;
|
|
13511
|
+
var PACKET_LEDGER_RETAINED = 2e3;
|
|
13512
|
+
function rememberInLedger(ledger, value) {
|
|
13513
|
+
ledger.add(value);
|
|
13514
|
+
if (ledger.size <= PACKET_LEDGER_HIGH_WATER) return;
|
|
13515
|
+
let excess = ledger.size - PACKET_LEDGER_RETAINED;
|
|
13516
|
+
for (const oldest of ledger) {
|
|
13517
|
+
if (excess-- <= 0) break;
|
|
13518
|
+
ledger.delete(oldest);
|
|
13519
|
+
}
|
|
13520
|
+
}
|
|
13396
13521
|
var DIRECT_RECOVERED_VIDEO_QUEUE_LIMIT = 512;
|
|
13397
13522
|
var DIRECT_RECOVERED_AUDIO_QUEUE_LIMIT = 512;
|
|
13398
13523
|
var MmtpRouter = class {
|
|
@@ -13430,16 +13555,13 @@ var MmtpRouter = class {
|
|
|
13430
13555
|
// identity keeps renditions that reuse a packet ID from opening each other's gate.
|
|
13431
13556
|
#trackSynced = /* @__PURE__ */ new Set();
|
|
13432
13557
|
#droppedPreSyncVideo = /* @__PURE__ */ new Set();
|
|
13433
|
-
//
|
|
13434
|
-
//
|
|
13435
|
-
//
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
// An overlap copy and its multicast twin carry the same symbol, and the copy
|
|
13441
|
-
// never feeds FEC, so FEC's first-arrival check cannot dedup the pair.
|
|
13442
|
-
#parsedSourceSymbols = /* @__PURE__ */ new Set();
|
|
13558
|
+
// One entry per physical stream (packetId, catalog track name): its stable
|
|
13559
|
+
// JSON key and its per-packet duplicate ledgers. The ledgers used to be
|
|
13560
|
+
// three router-wide Sets of "<streamKey>:<coordinates>" strings, so every
|
|
13561
|
+
// packet built and hashed up to three strings, and resetTrack() scanned
|
|
13562
|
+
// every retained key by prefix (BLO-36599). They now hold the wire numbers
|
|
13563
|
+
// themselves, and a reset clears one stream's Sets.
|
|
13564
|
+
#streams = /* @__PURE__ */ new Map();
|
|
13443
13565
|
// Live WebCodecs callbacks cannot accept late recovered inter-frame video.
|
|
13444
13566
|
// MSE recovery routes through CmafBlockAssembler and can reorder by block; the
|
|
13445
13567
|
// direct callback path has to preserve decode order before frames leave libmmt.
|
|
@@ -13970,11 +14092,15 @@ var MmtpRouter = class {
|
|
|
13970
14092
|
*/
|
|
13971
14093
|
feedRepairPacket(packet, ownerPacketIdHint, catalogTrackName) {
|
|
13972
14094
|
if (this.#disposed) return;
|
|
13973
|
-
|
|
14095
|
+
let header;
|
|
14096
|
+
try {
|
|
14097
|
+
header = parseMMTPHeader(packet);
|
|
14098
|
+
} catch {
|
|
14099
|
+
return;
|
|
14100
|
+
}
|
|
14101
|
+
const parsed = parseMoqRepairFrameWithHeader(packet, header);
|
|
13974
14102
|
if (!parsed) return;
|
|
13975
|
-
const
|
|
13976
|
-
const repairPacketId = header?.packetId;
|
|
13977
|
-
if (repairPacketId == null) return;
|
|
14103
|
+
const repairPacketId = header.packetId;
|
|
13978
14104
|
const hintedOwner = ownerPacketIdHint != null && this.#classifyPacketId(ownerPacketIdHint) !== null ? ownerPacketIdHint : null;
|
|
13979
14105
|
const ownerPacketId = hintedOwner ?? (this.#classifyPacketId(repairPacketId) !== null ? repairPacketId : null);
|
|
13980
14106
|
if (ownerPacketId === null) {
|
|
@@ -13999,7 +14125,7 @@ var MmtpRouter = class {
|
|
|
13999
14125
|
ownerPacketId,
|
|
14000
14126
|
repairSbn,
|
|
14001
14127
|
repairEsi,
|
|
14002
|
-
parsed.
|
|
14128
|
+
parsed.symbolData,
|
|
14003
14129
|
"moq",
|
|
14004
14130
|
catalogTrackName
|
|
14005
14131
|
)) return;
|
|
@@ -14008,13 +14134,13 @@ var MmtpRouter = class {
|
|
|
14008
14134
|
parsed.ssStart,
|
|
14009
14135
|
parsed.ssbLength,
|
|
14010
14136
|
parsed.rsId,
|
|
14011
|
-
parsed.
|
|
14137
|
+
parsed.symbolData
|
|
14012
14138
|
) : this.#fecManager.feedRepairSymbol(
|
|
14013
14139
|
ownerPacketId,
|
|
14014
14140
|
parsed.ssStart,
|
|
14015
14141
|
parsed.ssbLength,
|
|
14016
14142
|
parsed.rsId,
|
|
14017
|
-
parsed.
|
|
14143
|
+
parsed.symbolData,
|
|
14018
14144
|
catalogTrackName
|
|
14019
14145
|
);
|
|
14020
14146
|
if (recovered) {
|
|
@@ -14121,16 +14247,10 @@ var MmtpRouter = class {
|
|
|
14121
14247
|
this.#lastDirectEmittedAudioCursorByStream.delete(streamKey);
|
|
14122
14248
|
this.#pendingDirectRecoveredAudioByStream.delete(streamKey);
|
|
14123
14249
|
this.#manifestRecoveryQueues.delete(streamKey);
|
|
14124
|
-
const
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
this.#parsedSourceSymbols
|
|
14129
|
-
]) {
|
|
14130
|
-
for (const key of packetSeqs) {
|
|
14131
|
-
if (key.startsWith(streamPrefix)) packetSeqs.delete(key);
|
|
14132
|
-
}
|
|
14133
|
-
}
|
|
14250
|
+
const ledgers = this.#stream(packetId, catalogTrackName);
|
|
14251
|
+
ledgers.sourceSeqs.clear();
|
|
14252
|
+
ledgers.routedSeqs.clear();
|
|
14253
|
+
ledgers.parsedSymbols.clear();
|
|
14134
14254
|
const assemblersToReset = /* @__PURE__ */ new Set();
|
|
14135
14255
|
const exactAssembler = this.#mseAssemblers.get(streamKey);
|
|
14136
14256
|
if (exactAssembler) assemblersToReset.add(exactAssembler);
|
|
@@ -14146,9 +14266,7 @@ var MmtpRouter = class {
|
|
|
14146
14266
|
this.#disposed = true;
|
|
14147
14267
|
this.cancelKeyframeLostTimer();
|
|
14148
14268
|
this.#parser.dispose();
|
|
14149
|
-
this.#
|
|
14150
|
-
this.#routedPacketSeqs.clear();
|
|
14151
|
-
this.#parsedSourceSymbols.clear();
|
|
14269
|
+
this.#streams.clear();
|
|
14152
14270
|
this.#trackPacketCallbacks.clear();
|
|
14153
14271
|
this.#latestVideoSeqByStream.clear();
|
|
14154
14272
|
this.#lastDirectSourceVideoTsByStream.clear();
|
|
@@ -14248,8 +14366,9 @@ var MmtpRouter = class {
|
|
|
14248
14366
|
* 2. feed() → MFU extraction, reassembly, keyframe detection, emit via callbacks
|
|
14249
14367
|
*/
|
|
14250
14368
|
#processMMTP(packet, source, manifestIdentity, manifestAdmitted = false, ingress, overlapCopy = false) {
|
|
14251
|
-
const
|
|
14252
|
-
if (!
|
|
14369
|
+
const parsed = this.#parser.parsePacket(packet);
|
|
14370
|
+
if (!parsed) return;
|
|
14371
|
+
const info = parsed.info;
|
|
14253
14372
|
if (source === "multicast" && !ingressHasPacketId(ingress, info.packetId)) {
|
|
14254
14373
|
debugRouter(
|
|
14255
14374
|
`[MmtpRouter] Dropping multicast packet pid=${info.packetId}: absent from ingress tracks`
|
|
@@ -14303,8 +14422,8 @@ var MmtpRouter = class {
|
|
|
14303
14422
|
}
|
|
14304
14423
|
}
|
|
14305
14424
|
if (info.isRepair) {
|
|
14306
|
-
const
|
|
14307
|
-
if (!
|
|
14425
|
+
const repair = parseMoqRepairFrameWithHeader(packet, parsed.header);
|
|
14426
|
+
if (!repair) return;
|
|
14308
14427
|
const ownerPacketId = this.#resolveRepairOwnerPacketId(info.packetId, ingress);
|
|
14309
14428
|
if (ownerPacketId != null && this.#fecManager) {
|
|
14310
14429
|
if (hasAmbiguousCatalogTrackName(ingress, ownerPacketId)) return;
|
|
@@ -14312,17 +14431,17 @@ var MmtpRouter = class {
|
|
|
14312
14431
|
const count = this.#repairPidCounts[info.packetId];
|
|
14313
14432
|
if (count <= 2 || count % 500 === 0) {
|
|
14314
14433
|
console.log(
|
|
14315
|
-
`[MC-PKT] pid=${info.packetId} repairOwner=${ownerPacketId} type=${info.packetType} count=${count} ssbLength=${
|
|
14434
|
+
`[MC-PKT] pid=${info.packetId} repairOwner=${ownerPacketId} type=${info.packetType} count=${count} ssbLength=${repair.ssbLength} len=${packet.length}`
|
|
14316
14435
|
);
|
|
14317
14436
|
}
|
|
14318
|
-
const repairSbn = this.#deriveRepairSbn(
|
|
14437
|
+
const repairSbn = this.#deriveRepairSbn(repair.ssStart, repair.ssbLength, ownerPacketId);
|
|
14319
14438
|
if (repairSbn === null) return;
|
|
14320
|
-
const repairEsi = this.#kForPacket(ownerPacketId) +
|
|
14439
|
+
const repairEsi = this.#kForPacket(ownerPacketId) + repair.rsId;
|
|
14321
14440
|
if (!this.#feedFecTransportSymbol(
|
|
14322
14441
|
ownerPacketId,
|
|
14323
14442
|
repairSbn,
|
|
14324
14443
|
repairEsi,
|
|
14325
|
-
|
|
14444
|
+
repair.symbolData,
|
|
14326
14445
|
source,
|
|
14327
14446
|
catalogTrackNameForPacket(ingress, ownerPacketId)
|
|
14328
14447
|
)) return;
|
|
@@ -14338,16 +14457,16 @@ var MmtpRouter = class {
|
|
|
14338
14457
|
}
|
|
14339
14458
|
const recovered = repairCatalogTrackName === void 0 ? this.#fecManager.feedRepairSymbol(
|
|
14340
14459
|
ownerPacketId,
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14460
|
+
repair.ssStart,
|
|
14461
|
+
repair.ssbLength,
|
|
14462
|
+
repair.rsId,
|
|
14463
|
+
repair.symbolData
|
|
14345
14464
|
) : this.#fecManager.feedRepairSymbol(
|
|
14346
14465
|
ownerPacketId,
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14466
|
+
repair.ssStart,
|
|
14467
|
+
repair.ssbLength,
|
|
14468
|
+
repair.rsId,
|
|
14469
|
+
repair.symbolData,
|
|
14351
14470
|
repairCatalogTrackName
|
|
14352
14471
|
);
|
|
14353
14472
|
if (recovered) {
|
|
@@ -14399,7 +14518,6 @@ var MmtpRouter = class {
|
|
|
14399
14518
|
let sourceSymbolAccepted = false;
|
|
14400
14519
|
let sourceSymbolTrackable = false;
|
|
14401
14520
|
let parseSourceSymbol = false;
|
|
14402
|
-
let symbolKey;
|
|
14403
14521
|
const catalogTrackName = catalogTrackNameForPacket(ingress, info.packetId);
|
|
14404
14522
|
if (catalogTrackName !== void 0) {
|
|
14405
14523
|
const names = this.#catalogTrackNamesByPacketId.get(info.packetId) ?? /* @__PURE__ */ new Set();
|
|
@@ -14412,7 +14530,6 @@ var MmtpRouter = class {
|
|
|
14412
14530
|
const rawSymbol = packet.subarray(0, packet.length - 4);
|
|
14413
14531
|
const oversized = symbolSize > 0 && rawSymbol.length > symbolSize;
|
|
14414
14532
|
const coords = this.#deriveSbnEsi(fecId.ssId, info.packetId);
|
|
14415
|
-
symbolKey = `${this.#mediaStreamKey(info.packetId, catalogTrackName)}:${coords.sbn}:${coords.esi}`;
|
|
14416
14533
|
let overlapBlockCompleted = false;
|
|
14417
14534
|
if (overlapCopy) {
|
|
14418
14535
|
overlapBlockCompleted = catalogTrackName === void 0 ? this.#fecManager.isBlockCompleted(coords.sbn, info.packetId) : this.#fecManager.isBlockCompleted(
|
|
@@ -14445,11 +14562,16 @@ var MmtpRouter = class {
|
|
|
14445
14562
|
sourceFec = { ssId: fecId.ssId, sbn: coords.sbn, symbolData };
|
|
14446
14563
|
}
|
|
14447
14564
|
}
|
|
14448
|
-
parseSourceSymbol = (overlapCopy ? !overlapBlockCompleted : sourceSymbolAccepted) && !this.#
|
|
14565
|
+
parseSourceSymbol = (overlapCopy ? !overlapBlockCompleted : sourceSymbolAccepted) && !this.#stream(info.packetId, catalogTrackName).parsedSymbols.has(fecId.ssId);
|
|
14449
14566
|
fecInfo = { sbn: coords.sbn, esi: coords.esi, oversized };
|
|
14450
14567
|
}
|
|
14451
14568
|
if (!this.#fecManager || !info.fecPayloadId || parseSourceSymbol) {
|
|
14452
|
-
if (
|
|
14569
|
+
if (this.#fecManager && info.fecPayloadId) {
|
|
14570
|
+
rememberInLedger(
|
|
14571
|
+
this.#stream(info.packetId, catalogTrackName).parsedSymbols,
|
|
14572
|
+
info.fecPayloadId.ssId
|
|
14573
|
+
);
|
|
14574
|
+
}
|
|
14453
14575
|
this.#noteSourcePacketSeq(
|
|
14454
14576
|
info.packetId,
|
|
14455
14577
|
info.sequenceNumber,
|
|
@@ -14463,7 +14585,7 @@ var MmtpRouter = class {
|
|
|
14463
14585
|
this.#feedViaParser(packet, info, fecInfo, {
|
|
14464
14586
|
source,
|
|
14465
14587
|
catalogTrackName
|
|
14466
|
-
});
|
|
14588
|
+
}, parsed);
|
|
14467
14589
|
}
|
|
14468
14590
|
if (this.#fecManager && info.fecPayloadId && sourceSymbolAccepted && sourceSymbolTrackable) {
|
|
14469
14591
|
const { sbn, esi } = this.#deriveSbnEsi(
|
|
@@ -14539,7 +14661,7 @@ var MmtpRouter = class {
|
|
|
14539
14661
|
* Set temp context and delegate to parser.feed() for MFU extraction,
|
|
14540
14662
|
* reassembly, keyframe detection, and frame emission via callbacks.
|
|
14541
14663
|
*/
|
|
14542
|
-
#feedViaParser(packet, info, fecInfo, parserOptions) {
|
|
14664
|
+
#feedViaParser(packet, info, fecInfo, parserOptions, parsed) {
|
|
14543
14665
|
const diag = this.#diagFor(info.packetId, parserOptions?.catalogTrackName);
|
|
14544
14666
|
const fragmentsBefore = this.#parser.reassemblerFragmentsFed;
|
|
14545
14667
|
const reassembledBefore = this.#parser.reassemblerDataUnitsReturned;
|
|
@@ -14550,13 +14672,15 @@ var MmtpRouter = class {
|
|
|
14550
14672
|
this.#currentFecInfo = fecInfo;
|
|
14551
14673
|
this.#currentSeqNum = info.sequenceNumber;
|
|
14552
14674
|
try {
|
|
14553
|
-
|
|
14675
|
+
const feedOptions = {
|
|
14554
14676
|
skipFecPayloadId: parserOptions?.skipFecPayloadId,
|
|
14555
14677
|
recovered: parserOptions?.recovered,
|
|
14556
14678
|
source: parserOptions?.source,
|
|
14557
14679
|
deliveryProvenance: parserOptions?.deliveryProvenance,
|
|
14558
14680
|
catalogTrackName: parserOptions?.catalogTrackName
|
|
14559
|
-
}
|
|
14681
|
+
};
|
|
14682
|
+
if (parsed) this.#parser.feedParsed(packet, parsed, feedOptions);
|
|
14683
|
+
else this.#parser.feed(packet, feedOptions);
|
|
14560
14684
|
} finally {
|
|
14561
14685
|
this.#currentFecInfo = void 0;
|
|
14562
14686
|
}
|
|
@@ -14629,41 +14753,21 @@ var MmtpRouter = class {
|
|
|
14629
14753
|
}
|
|
14630
14754
|
#noteSourcePacketSeq(packetId, packetSequenceNumber, catalogTrackName) {
|
|
14631
14755
|
if (packetSequenceNumber === void 0 || !Number.isFinite(packetSequenceNumber)) return;
|
|
14632
|
-
|
|
14633
|
-
this.#
|
|
14756
|
+
rememberInLedger(
|
|
14757
|
+
this.#stream(packetId, catalogTrackName).sourceSeqs,
|
|
14758
|
+
packetSequenceNumber
|
|
14634
14759
|
);
|
|
14635
|
-
if (this.#sourcePktSeqs.size > 4e3) {
|
|
14636
|
-
const iter = this.#sourcePktSeqs.values();
|
|
14637
|
-
for (let i = 0; i < 2e3; i++) iter.next();
|
|
14638
|
-
const keep = /* @__PURE__ */ new Set();
|
|
14639
|
-
for (const v of iter) keep.add(v);
|
|
14640
|
-
this.#sourcePktSeqs = keep;
|
|
14641
|
-
}
|
|
14642
14760
|
}
|
|
14643
|
-
#
|
|
14644
|
-
this.#
|
|
14645
|
-
if (this.#parsedSourceSymbols.size > 4e3) {
|
|
14646
|
-
const iter = this.#parsedSourceSymbols.values();
|
|
14647
|
-
for (let i = 0; i < 2e3; i++) iter.next();
|
|
14648
|
-
const keep = /* @__PURE__ */ new Set();
|
|
14649
|
-
for (const v of iter) keep.add(v);
|
|
14650
|
-
this.#parsedSourceSymbols = keep;
|
|
14651
|
-
}
|
|
14761
|
+
#sourceSeqReceived(packetId, packetSequenceNumber, catalogTrackName) {
|
|
14762
|
+
return this.#stream(packetId, catalogTrackName).sourceSeqs.has(packetSequenceNumber);
|
|
14652
14763
|
}
|
|
14653
14764
|
#routeTrackPacket(packet, packetId, packetSequenceNumber, meta) {
|
|
14654
14765
|
if (!Number.isFinite(packetSequenceNumber)) return;
|
|
14655
14766
|
const callback = this.#trackPacketCallbacks.get(packetId);
|
|
14656
14767
|
if (!callback) return;
|
|
14657
|
-
const
|
|
14658
|
-
if (
|
|
14659
|
-
|
|
14660
|
-
if (this.#routedPacketSeqs.size > 4e3) {
|
|
14661
|
-
const iter = this.#routedPacketSeqs.values();
|
|
14662
|
-
for (let i = 0; i < 2e3; i++) iter.next();
|
|
14663
|
-
const keep = /* @__PURE__ */ new Set();
|
|
14664
|
-
for (const value of iter) keep.add(value);
|
|
14665
|
-
this.#routedPacketSeqs = keep;
|
|
14666
|
-
}
|
|
14768
|
+
const routedSeqs = this.#stream(packetId, meta.catalogTrackName).routedSeqs;
|
|
14769
|
+
if (routedSeqs.has(packetSequenceNumber)) return;
|
|
14770
|
+
rememberInLedger(routedSeqs, packetSequenceNumber);
|
|
14667
14771
|
callback(packet, {
|
|
14668
14772
|
packetId,
|
|
14669
14773
|
packetSequenceNumber,
|
|
@@ -14685,17 +14789,26 @@ var MmtpRouter = class {
|
|
|
14685
14789
|
* of pairs is bounded by the catalog (BLO-36599).
|
|
14686
14790
|
*/
|
|
14687
14791
|
#mediaStreamKey(packetId, catalogTrackName) {
|
|
14688
|
-
|
|
14792
|
+
return this.#stream(packetId, catalogTrackName).key;
|
|
14793
|
+
}
|
|
14794
|
+
/** The (packetId, catalog name) stream's key and duplicate ledgers. */
|
|
14795
|
+
#stream(packetId, catalogTrackName) {
|
|
14796
|
+
let byName = this.#streams.get(packetId);
|
|
14689
14797
|
if (!byName) {
|
|
14690
14798
|
byName = /* @__PURE__ */ new Map();
|
|
14691
|
-
this.#
|
|
14692
|
-
}
|
|
14693
|
-
let
|
|
14694
|
-
if (
|
|
14695
|
-
|
|
14696
|
-
|
|
14799
|
+
this.#streams.set(packetId, byName);
|
|
14800
|
+
}
|
|
14801
|
+
let stream = byName.get(catalogTrackName);
|
|
14802
|
+
if (stream === void 0) {
|
|
14803
|
+
stream = {
|
|
14804
|
+
key: JSON.stringify([packetId, catalogTrackName ?? null]),
|
|
14805
|
+
sourceSeqs: /* @__PURE__ */ new Set(),
|
|
14806
|
+
routedSeqs: /* @__PURE__ */ new Set(),
|
|
14807
|
+
parsedSymbols: /* @__PURE__ */ new Set()
|
|
14808
|
+
};
|
|
14809
|
+
byName.set(catalogTrackName, stream);
|
|
14697
14810
|
}
|
|
14698
|
-
return
|
|
14811
|
+
return stream;
|
|
14699
14812
|
}
|
|
14700
14813
|
#packetIdFromStreamKey(key) {
|
|
14701
14814
|
try {
|
|
@@ -14740,9 +14853,6 @@ var MmtpRouter = class {
|
|
|
14740
14853
|
if (scaled === null) return null;
|
|
14741
14854
|
return { authoredTiming, timestamp: scaled.timestamp, mmtpTimestamp };
|
|
14742
14855
|
}
|
|
14743
|
-
#packetSeqKey(packetId, packetSequenceNumber, catalogTrackName) {
|
|
14744
|
-
return `${this.#mediaStreamKey(packetId, catalogTrackName)}:${packetSequenceNumber}`;
|
|
14745
|
-
}
|
|
14746
14856
|
#pendingRecoveredKey(meta) {
|
|
14747
14857
|
return `${meta.timestamp}:${meta.packetSequenceNumber ?? ""}`;
|
|
14748
14858
|
}
|
|
@@ -15060,9 +15170,7 @@ var MmtpRouter = class {
|
|
|
15060
15170
|
if (sym.fragmentType === 0 || sym.fragmentType === 1) continue;
|
|
15061
15171
|
const fi = sym.fragment.fragmentationIndicator;
|
|
15062
15172
|
if (fi === 0) {
|
|
15063
|
-
if (this.#
|
|
15064
|
-
this.#packetSeqKey(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)
|
|
15065
|
-
)) {
|
|
15173
|
+
if (this.#sourceSeqReceived(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)) {
|
|
15066
15174
|
dedupedAgainstSource2++;
|
|
15067
15175
|
continue;
|
|
15068
15176
|
}
|
|
@@ -15112,9 +15220,7 @@ var MmtpRouter = class {
|
|
|
15112
15220
|
});
|
|
15113
15221
|
this.#noteEmittedKeyframe(ownerPacketId, keyframe);
|
|
15114
15222
|
} else {
|
|
15115
|
-
if (this.#
|
|
15116
|
-
this.#packetSeqKey(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)
|
|
15117
|
-
)) {
|
|
15223
|
+
if (this.#sourceSeqReceived(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)) {
|
|
15118
15224
|
dedupedAgainstSource2++;
|
|
15119
15225
|
continue;
|
|
15120
15226
|
}
|
|
@@ -15242,9 +15348,7 @@ var MmtpRouter = class {
|
|
|
15242
15348
|
if (isVideo) {
|
|
15243
15349
|
const fi = sym.fragment.fragmentationIndicator;
|
|
15244
15350
|
if (fi === 0) {
|
|
15245
|
-
if (this.#
|
|
15246
|
-
this.#packetSeqKey(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)
|
|
15247
|
-
)) {
|
|
15351
|
+
if (this.#sourceSeqReceived(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)) {
|
|
15248
15352
|
dedupedAgainstSource++;
|
|
15249
15353
|
continue;
|
|
15250
15354
|
}
|
|
@@ -15289,9 +15393,7 @@ var MmtpRouter = class {
|
|
|
15289
15393
|
...catalogTrackName === void 0 ? {} : { catalogTrackName }
|
|
15290
15394
|
});
|
|
15291
15395
|
} else {
|
|
15292
|
-
if (this.#
|
|
15293
|
-
this.#packetSeqKey(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)
|
|
15294
|
-
)) {
|
|
15396
|
+
if (this.#sourceSeqReceived(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)) {
|
|
15295
15397
|
dedupedAgainstSource++;
|
|
15296
15398
|
continue;
|
|
15297
15399
|
}
|
|
@@ -15370,9 +15472,7 @@ var MmtpRouter = class {
|
|
|
15370
15472
|
}
|
|
15371
15473
|
}
|
|
15372
15474
|
} else {
|
|
15373
|
-
if (this.#
|
|
15374
|
-
this.#packetSeqKey(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)
|
|
15375
|
-
)) {
|
|
15475
|
+
if (this.#sourceSeqReceived(ownerPacketId, sym.packetSequenceNumber, catalogTrackName)) {
|
|
15376
15476
|
dedupedAgainstSource++;
|
|
15377
15477
|
continue;
|
|
15378
15478
|
}
|
|
@@ -17234,10 +17334,8 @@ var MulticastTransport = class _MulticastTransport {
|
|
|
17234
17334
|
this.#packetIds = null;
|
|
17235
17335
|
}
|
|
17236
17336
|
#acceptPacket(packet) {
|
|
17237
|
-
|
|
17238
|
-
|
|
17239
|
-
packetId = parseMMTPHeader(packet).packetId;
|
|
17240
|
-
} catch {
|
|
17337
|
+
const packetId = readMMTPPacketId(packet);
|
|
17338
|
+
if (packetId === null) {
|
|
17241
17339
|
if (!this.#packetIds) return true;
|
|
17242
17340
|
this.#stats.packetsDroppedUnparseable++;
|
|
17243
17341
|
return false;
|